From: Ricardo Carrano Date: Thu, 17 Jul 2008 18:28:07 +0000 (+0000) Subject: adding the patch file too X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=refs%2Fheads%2Flibertas;p=linux-2.6.git adding the patch file too --- diff --git a/linux-2.6-300-olpc.patch b/linux-2.6-300-olpc.patch new file mode 100644 index 000000000..a09c015a5 --- /dev/null +++ b/linux-2.6-300-olpc.patch @@ -0,0 +1,26873 @@ +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/11d.c linux-2.6.22-300/drivers/net/wireless/libertas/11d.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/11d.c 2008-07-17 00:17:57.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/11d.c 2008-06-05 18:10:06.000000000 -0400 +@@ -43,16 +43,14 @@ static struct chan_freq_power channel_fr + {14, 2484, TX_PWR_DEFAULT} + }; + +-static u8 wlan_region_2_code(u8 * region) ++static u8 lbs_region_2_code(u8 *region) + { + u8 i; +- u8 size = sizeof(region_code_mapping)/ +- sizeof(struct region_code_mapping); + + for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) + region[i] = toupper(region[i]); + +- for (i = 0; i < size; i++) { ++ for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { + if (!memcmp(region, region_code_mapping[i].region, + COUNTRY_CODE_LEN)) + return (region_code_mapping[i].code); +@@ -62,12 +60,11 @@ static u8 wlan_region_2_code(u8 * region + return (region_code_mapping[0].code); + } + +-static u8 *wlan_code_2_region(u8 code) ++static u8 *lbs_code_2_region(u8 code) + { + u8 i; +- u8 size = sizeof(region_code_mapping) +- / sizeof(struct region_code_mapping); +- for (i = 0; i < size; i++) { ++ ++ for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { + if (region_code_mapping[i].code == code) + return (region_code_mapping[i].region); + } +@@ -82,7 +79,7 @@ static u8 *wlan_code_2_region(u8 code) + * @param nrchan number of channels + * @return the nrchan-th chan number + */ +-static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) ++static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan) + /*find the nrchan-th chan after the firstchan*/ + { + u8 i; +@@ -90,8 +87,7 @@ static u8 wlan_get_chan_11d(u8 band, u8 + u8 cfp_no; + + cfp = channel_freq_power_UN_BG; +- cfp_no = sizeof(channel_freq_power_UN_BG) / +- sizeof(struct chan_freq_power); ++ cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG); + + for (i = 0; i < cfp_no; i++) { + if ((cfp + i)->channel == firstchan) { +@@ -117,40 +113,36 @@ static u8 wlan_get_chan_11d(u8 band, u8 + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return TRUE; FALSE + */ +-static u8 wlan_channel_known_11d(u8 chan, ++static u8 lbs_channel_known_11d(u8 chan, + struct parsed_region_chan_11d * parsed_region_chan) + { + struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; + u8 nr_chan = parsed_region_chan->nr_chan; + u8 i = 0; + +- lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr, ++ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr, + sizeof(struct chan_power_11d) * nr_chan); + + for (i = 0; i < nr_chan; i++) { + if (chan == chanpwr[i].chan) { +- lbs_deb_11d("11D: Found Chan:%d\n", chan); ++ lbs_deb_11d("found chan %d\n", chan); + return 1; + } + } + +- lbs_deb_11d("11D: Not Find Chan:%d\n", chan); ++ lbs_deb_11d("chan %d not found\n", chan); + return 0; + } + +-u32 libertas_chan_2_freq(u8 chan, u8 band) ++u32 lbs_chan_2_freq(u8 chan, u8 band) + { + struct chan_freq_power *cf; +- u16 cnt; + u16 i; + u32 freq = 0; + + cf = channel_freq_power_UN_BG; +- cnt = +- sizeof(channel_freq_power_UN_BG) / +- sizeof(struct chan_freq_power); + +- for (i = 0; i < cnt; i++) { ++ for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) { + if (chan == cf[i].channel) + freq = cf[i].freq; + } +@@ -160,7 +152,7 @@ u32 libertas_chan_2_freq(u8 chan, u8 ban + + static int generate_domain_info_11d(struct parsed_region_chan_11d + *parsed_region_chan, +- struct wlan_802_11d_domain_reg * domaininfo) ++ struct lbs_802_11d_domain_reg *domaininfo) + { + u8 nr_subband = 0; + +@@ -174,8 +166,8 @@ static int generate_domain_info_11d(stru + memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, + COUNTRY_CODE_LEN); + +- lbs_deb_11d("11D:nrchan=%d\n", nr_chan); +- lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan, ++ lbs_deb_11d("nrchan %d\n", nr_chan); ++ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan, + sizeof(struct parsed_region_chan_11d)); + + for (i = 0; i < nr_chan; i++) { +@@ -213,7 +205,7 @@ static int generate_domain_info_11d(stru + domaininfo->nr_subband = nr_subband; + + lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); +- lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo, ++ lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, + COUNTRY_CODE_LEN + 1 + + sizeof(struct ieeetypes_subbandset) * nr_subband); + return 0; +@@ -225,7 +217,7 @@ static int generate_domain_info_11d(stru + * @param *parsed_region_chan pointer to parsed_region_chan_11d + * @return N/A + */ +-static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan, ++static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan, + struct parsed_region_chan_11d * + parsed_region_chan) + { +@@ -233,34 +225,34 @@ static void wlan_generate_parsed_region_ + struct chan_freq_power *cfp; + + if (region_chan == NULL) { +- lbs_deb_11d("11D: region_chan is NULL\n"); ++ lbs_deb_11d("region_chan is NULL\n"); + return; + } + + cfp = region_chan->CFP; + if (cfp == NULL) { +- lbs_deb_11d("11D: cfp equal NULL \n"); ++ lbs_deb_11d("cfp is NULL \n"); + return; + } + + parsed_region_chan->band = region_chan->band; + parsed_region_chan->region = region_chan->region; + memcpy(parsed_region_chan->countrycode, +- wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); ++ lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN); + +- lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region, ++ lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region, + parsed_region_chan->band); + + for (i = 0; i < region_chan->nrcfp; i++, cfp++) { + parsed_region_chan->chanpwr[i].chan = cfp->channel; + parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; +- lbs_deb_11d("11D: Chan[%d] Pwr[%d]\n", ++ lbs_deb_11d("chan %d, pwr %d\n", + parsed_region_chan->chanpwr[i].chan, + parsed_region_chan->chanpwr[i].pwr); + } + parsed_region_chan->nr_chan = region_chan->nrcfp; + +- lbs_deb_11d("11D: nrchan[%d]\n", parsed_region_chan->nr_chan); ++ lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan); + + return; + } +@@ -272,7 +264,7 @@ static void wlan_generate_parsed_region_ + * @param chan chan + * @return TRUE;FALSE + */ +-static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) ++static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan) + { + struct chan_freq_power *cfp; + int cfp_no; +@@ -281,7 +273,7 @@ static u8 wlan_region_chan_supported_11d + + lbs_deb_enter(LBS_DEB_11D); + +- cfp = libertas_get_region_cfp_table(region, band, &cfp_no); ++ cfp = lbs_get_region_cfp_table(region, band, &cfp_no); + if (cfp == NULL) + return 0; + +@@ -336,7 +328,7 @@ static int parse_domain_info_11d(struct + 6. Others + */ + +- lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30); ++ lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); + + if ((*(countryinfo->countrycode)) == 0 + || (countryinfo->len <= COUNTRY_CODE_LEN)) { +@@ -346,10 +338,10 @@ static int parse_domain_info_11d(struct + + /*Step1: check region_code */ + parsed_region_chan->region = region = +- wlan_region_2_code(countryinfo->countrycode); ++ lbs_region_2_code(countryinfo->countrycode); + + lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region); +- lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode, ++ lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode, + COUNTRY_CODE_LEN); + + parsed_region_chan->band = band; +@@ -364,7 +356,7 @@ static int parse_domain_info_11d(struct + + if (countryinfo->subband[j].firstchan <= lastchan) { + /*Step2&3. Check First Chan Num increment and no overlap */ +- lbs_deb_11d("11D: Chan[%d>%d] Overlap\n", ++ lbs_deb_11d("chan %d>%d, overlap\n", + countryinfo->subband[j].firstchan, lastchan); + continue; + } +@@ -375,7 +367,7 @@ static int parse_domain_info_11d(struct + for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { + /*step4: channel is supported? */ + +- if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) { ++ if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) { + /* Chan is not found in UN table */ + lbs_deb_11d("chan is not supported: %d \n", i); + break; +@@ -383,7 +375,7 @@ static int parse_domain_info_11d(struct + + lastchan = curchan; + +- if (wlan_region_chan_supported_11d ++ if (lbs_region_chan_supported_11d + (region, band, curchan)) { + /*step5: Check if curchan is supported by mrvl in region */ + parsed_region_chan->chanpwr[idx].chan = curchan; +@@ -393,7 +385,7 @@ static int parse_domain_info_11d(struct + } else { + /*not supported and ignore the chan */ + lbs_deb_11d( +- "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", ++ "i %d, chan %d unsupported in region %x, band %d\n", + i, curchan, region, band); + } + } +@@ -405,7 +397,7 @@ static int parse_domain_info_11d(struct + parsed_region_chan->nr_chan = idx; + + lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan); +- lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan, ++ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan, + 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); + + done: +@@ -419,18 +411,18 @@ done: + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return PASSIVE if chan is unknown; ACTIVE if chan is known + */ +-u8 libertas_get_scan_type_11d(u8 chan, ++u8 lbs_get_scan_type_11d(u8 chan, + struct parsed_region_chan_11d * parsed_region_chan) + { +- u8 scan_type = cmd_scan_type_passive; ++ u8 scan_type = CMD_SCAN_TYPE_PASSIVE; + + lbs_deb_enter(LBS_DEB_11D); + +- if (wlan_channel_known_11d(chan, parsed_region_chan)) { +- lbs_deb_11d("11D: Found and do Active Scan\n"); +- scan_type = cmd_scan_type_active; ++ if (lbs_channel_known_11d(chan, parsed_region_chan)) { ++ lbs_deb_11d("found, do active scan\n"); ++ scan_type = CMD_SCAN_TYPE_ACTIVE; + } else { +- lbs_deb_11d("11D: Not Find and do Passive Scan\n"); ++ lbs_deb_11d("not found, do passive scan\n"); + } + + lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type); +@@ -438,80 +430,60 @@ u8 libertas_get_scan_type_11d(u8 chan, + + } + +-void libertas_init_11d(wlan_private * priv) ++void lbs_init_11d(struct lbs_private *priv) + { +- priv->adapter->enable11d = 0; +- memset(&(priv->adapter->parsed_region_chan), 0, ++ priv->enable11d = 0; ++ memset(&(priv->parsed_region_chan), 0, + sizeof(struct parsed_region_chan_11d)); + return; + } + +-static int wlan_enable_11d(wlan_private * priv, u8 flag) +-{ +- int ret; +- +- priv->adapter->enable11d = flag; +- +- /* send cmd to FW to enable/disable 11D function in FW */ +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_snmp_mib, +- cmd_act_set, +- cmd_option_waitforrsp, +- OID_802_11D_ENABLE, +- &priv->adapter->enable11d); +- if (ret) +- lbs_deb_11d("11D: Fail to enable 11D \n"); +- +- return 0; +-} +- + /** + * @brief This function sets DOMAIN INFO to FW +- * @param priv pointer to wlan_private ++ * @param priv pointer to struct lbs_private + * @return 0; -1 + */ +-static int set_domain_info_11d(wlan_private * priv) ++static int set_domain_info_11d(struct lbs_private *priv) + { + int ret; + +- if (!priv->adapter->enable11d) { +- lbs_deb_11d("11D: dnld domain Info with 11d disabled\n"); ++ if (!priv->enable11d) { ++ lbs_deb_11d("dnld domain Info with 11d disabled\n"); + return 0; + } + +- ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info, +- cmd_act_set, +- cmd_option_waitforrsp, 0, NULL); ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, ++ CMD_ACT_SET, ++ CMD_OPTION_WAITFORRSP, 0, NULL); + if (ret) +- lbs_deb_11d("11D: Fail to dnld domain Info\n"); ++ lbs_deb_11d("fail to dnld domain info\n"); + + return ret; + } + + /** + * @brief This function setups scan channels +- * @param priv pointer to wlan_private ++ * @param priv pointer to struct lbs_private + * @param band band + * @return 0 + */ +-int libertas_set_universaltable(wlan_private * priv, u8 band) ++int lbs_set_universaltable(struct lbs_private *priv, u8 band) + { +- wlan_adapter *adapter = priv->adapter; + u16 size = sizeof(struct chan_freq_power); + u16 i = 0; + +- memset(adapter->universal_channel, 0, +- sizeof(adapter->universal_channel)); ++ memset(priv->universal_channel, 0, ++ sizeof(priv->universal_channel)); + +- adapter->universal_channel[i].nrcfp = ++ priv->universal_channel[i].nrcfp = + sizeof(channel_freq_power_UN_BG) / size; +- lbs_deb_11d("11D: BG-band nrcfp=%d\n", +- adapter->universal_channel[i].nrcfp); ++ lbs_deb_11d("BG-band nrcfp %d\n", ++ priv->universal_channel[i].nrcfp); + +- adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; +- adapter->universal_channel[i].valid = 1; +- adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE; +- adapter->universal_channel[i].band = band; ++ priv->universal_channel[i].CFP = channel_freq_power_UN_BG; ++ priv->universal_channel[i].valid = 1; ++ priv->universal_channel[i].region = UNIVERSAL_REGION_CODE; ++ priv->universal_channel[i].band = band; + i++; + + return 0; +@@ -519,21 +491,20 @@ int libertas_set_universaltable(wlan_pri + + /** + * @brief This function implements command CMD_802_11D_DOMAIN_INFO +- * @param priv pointer to wlan_private ++ * @param priv pointer to struct lbs_private + * @param cmd pointer to cmd buffer + * @param cmdno cmd ID + * @param cmdOption cmd action + * @return 0 + */ +-int libertas_cmd_802_11d_domain_info(wlan_private * priv, ++int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, + struct cmd_ds_command *cmd, u16 cmdno, + u16 cmdoption) + { + struct cmd_ds_802_11d_domain_info *pdomaininfo = + &cmd->params.domaininfo; + struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; +- wlan_adapter *adapter = priv->adapter; +- u8 nr_subband = adapter->domainreg.nr_subband; ++ u8 nr_subband = priv->domainreg.nr_subband; + + lbs_deb_enter(LBS_DEB_11D); + +@@ -541,16 +512,16 @@ int libertas_cmd_802_11d_domain_info(wla + + cmd->command = cpu_to_le16(cmdno); + pdomaininfo->action = cpu_to_le16(cmdoption); +- if (cmdoption == cmd_act_get) { ++ if (cmdoption == CMD_ACT_GET) { + cmd->size = + cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); +- lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, +- (int)(cmd->size)); ++ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, ++ le16_to_cpu(cmd->size)); + goto done; + } + + domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); +- memcpy(domain->countrycode, adapter->domainreg.countrycode, ++ memcpy(domain->countrycode, priv->domainreg.countrycode, + sizeof(domain->countrycode)); + + domain->header.len = +@@ -558,7 +529,7 @@ int libertas_cmd_802_11d_domain_info(wla + sizeof(domain->countrycode)); + + if (nr_subband) { +- memcpy(domain->subband, adapter->domainreg.subband, ++ memcpy(domain->subband, priv->domainreg.subband, + nr_subband * sizeof(struct ieeetypes_subbandset)); + + cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + +@@ -570,7 +541,7 @@ int libertas_cmd_802_11d_domain_info(wla + cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); + } + +- lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size)); ++ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size)); + + done: + lbs_deb_enter(LBS_DEB_11D); +@@ -578,37 +549,12 @@ done: + } + + /** +- * @brief This function implements private cmd: enable/disable 11D +- * @param priv pointer to wlan_private +- * @param wrq pointer to user data +- * @return 0 or -1 +- */ +-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) +-{ +- int data = 0; +- int *val; +- +- lbs_deb_enter(LBS_DEB_11D); +- data = SUBCMD_DATA(wrq); +- +- lbs_deb_11d("enable 11D: %s\n", +- (data == 1) ? "enable" : "Disable"); +- +- wlan_enable_11d(priv, data); +- val = (int *)wrq->u.name; +- *val = priv->adapter->enable11d; +- +- lbs_deb_enter(LBS_DEB_11D); +- return 0; +-} +- +-/** + * @brief This function parses countryinfo from AP and download country info to FW +- * @param priv pointer to wlan_private ++ * @param priv pointer to struct lbs_private + * @param resp pointer to command response buffer + * @return 0; -1 + */ +-int libertas_ret_802_11d_domain_info(wlan_private * priv, ++int lbs_ret_802_11d_domain_info(struct lbs_private *priv, + struct cmd_ds_command *resp) + { + struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; +@@ -619,13 +565,13 @@ int libertas_ret_802_11d_domain_info(wla + + lbs_deb_enter(LBS_DEB_11D); + +- lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp, ++ lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp, + (int)le16_to_cpu(resp->size)); + + nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / + sizeof(struct ieeetypes_subbandset); + +- lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband); ++ lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); + + if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { + lbs_deb_11d("Invalid Numrer of Subband returned!!\n"); +@@ -633,10 +579,10 @@ int libertas_ret_802_11d_domain_info(wla + } + + switch (action) { +- case cmd_act_set: /*Proc Set action */ ++ case CMD_ACT_SET: /*Proc Set action */ + break; + +- case cmd_act_get: ++ case CMD_ACT_GET: + break; + default: + lbs_deb_11d("Invalid action:%d\n", domaininfo->action); +@@ -650,36 +596,35 @@ int libertas_ret_802_11d_domain_info(wla + + /** + * @brief This function parses countryinfo from AP and download country info to FW +- * @param priv pointer to wlan_private ++ * @param priv pointer to struct lbs_private + * @return 0; -1 + */ +-int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, ++int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, + struct bss_descriptor * bss) + { + int ret; +- wlan_adapter *adapter = priv->adapter; + + lbs_deb_enter(LBS_DEB_11D); +- if (priv->adapter->enable11d) { +- memset(&adapter->parsed_region_chan, 0, ++ if (priv->enable11d) { ++ memset(&priv->parsed_region_chan, 0, + sizeof(struct parsed_region_chan_11d)); + ret = parse_domain_info_11d(&bss->countryinfo, 0, +- &adapter->parsed_region_chan); ++ &priv->parsed_region_chan); + + if (ret == -1) { +- lbs_deb_11d("11D: Err Parse domain_info from AP..\n"); ++ lbs_deb_11d("error parsing domain_info from AP\n"); + goto done; + } + +- memset(&adapter->domainreg, 0, +- sizeof(struct wlan_802_11d_domain_reg)); +- generate_domain_info_11d(&adapter->parsed_region_chan, +- &adapter->domainreg); ++ memset(&priv->domainreg, 0, ++ sizeof(struct lbs_802_11d_domain_reg)); ++ generate_domain_info_11d(&priv->parsed_region_chan, ++ &priv->domainreg); + + ret = set_domain_info_11d(priv); + + if (ret) { +- lbs_deb_11d("11D: Err set domainInfo to FW\n"); ++ lbs_deb_11d("error setting domain info\n"); + goto done; + } + } +@@ -692,60 +637,57 @@ done: + + /** + * @brief This function generates 11D info from user specified regioncode and download to FW +- * @param priv pointer to wlan_private ++ * @param priv pointer to struct lbs_private + * @return 0; -1 + */ +-int libertas_create_dnld_countryinfo_11d(wlan_private * priv) ++int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv) + { + int ret; +- wlan_adapter *adapter = priv->adapter; + struct region_channel *region_chan; + u8 j; + + lbs_deb_enter(LBS_DEB_11D); +- lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band); ++ lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band); + +- if (priv->adapter->enable11d) { ++ if (priv->enable11d) { + /* update parsed_region_chan_11; dnld domaininf to FW */ + +- for (j = 0; j < sizeof(adapter->region_channel) / +- sizeof(adapter->region_channel[0]); j++) { +- region_chan = &adapter->region_channel[j]; ++ for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) { ++ region_chan = &priv->region_channel[j]; + +- lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", j, ++ lbs_deb_11d("%d region_chan->band %d\n", j, + region_chan->band); + + if (!region_chan || !region_chan->valid + || !region_chan->CFP) + continue; +- if (region_chan->band != adapter->curbssparams.band) ++ if (region_chan->band != priv->curbssparams.band) + continue; + break; + } + +- if (j >= sizeof(adapter->region_channel) / +- sizeof(adapter->region_channel[0])) { +- lbs_deb_11d("11D:region_chan not found. band[%d]\n", +- adapter->curbssparams.band); ++ if (j >= ARRAY_SIZE(priv->region_channel)) { ++ lbs_deb_11d("region_chan not found, band %d\n", ++ priv->curbssparams.band); + ret = -1; + goto done; + } + +- memset(&adapter->parsed_region_chan, 0, ++ memset(&priv->parsed_region_chan, 0, + sizeof(struct parsed_region_chan_11d)); +- wlan_generate_parsed_region_chan_11d(region_chan, +- &adapter-> ++ lbs_generate_parsed_region_chan_11d(region_chan, ++ &priv-> + parsed_region_chan); + +- memset(&adapter->domainreg, 0, +- sizeof(struct wlan_802_11d_domain_reg)); +- generate_domain_info_11d(&adapter->parsed_region_chan, +- &adapter->domainreg); ++ memset(&priv->domainreg, 0, ++ sizeof(struct lbs_802_11d_domain_reg)); ++ generate_domain_info_11d(&priv->parsed_region_chan, ++ &priv->domainreg); + + ret = set_domain_info_11d(priv); + + if (ret) { +- lbs_deb_11d("11D: Err set domainInfo to FW\n"); ++ lbs_deb_11d("error setting domain info\n"); + goto done; + } + +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/11d.h linux-2.6.22-300/drivers/net/wireless/libertas/11d.h +--- linux-2.6.22-250/drivers/net/wireless/libertas/11d.h 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/11d.h 2008-06-05 18:10:06.000000000 -0400 +@@ -2,8 +2,8 @@ + * This header file contains data structures and + * function declarations of 802.11d + */ +-#ifndef _WLAN_11D_ +-#define _WLAN_11D_ ++#ifndef _LBS_11D_ ++#define _LBS_11D_ + + #include "types.h" + #include "defs.h" +@@ -52,7 +52,7 @@ struct cmd_ds_802_11d_domain_info { + } __attribute__ ((packed)); + + /** domain regulatory information */ +-struct wlan_802_11d_domain_reg { ++struct lbs_802_11d_domain_reg { + /** country Code*/ + u8 countrycode[COUNTRY_CODE_LEN]; + /** No. of subband*/ +@@ -78,30 +78,28 @@ struct region_code_mapping { + u8 code; + }; + +-u8 libertas_get_scan_type_11d(u8 chan, +- struct parsed_region_chan_11d *parsed_region_chan); ++struct lbs_private; + +-u32 libertas_chan_2_freq(u8 chan, u8 band); ++u8 lbs_get_scan_type_11d(u8 chan, ++ struct parsed_region_chan_11d *parsed_region_chan); + +-enum state_11d libertas_get_state_11d(wlan_private * priv); ++u32 lbs_chan_2_freq(u8 chan, u8 band); + +-void libertas_init_11d(wlan_private * priv); ++void lbs_init_11d(struct lbs_private *priv); + +-int libertas_set_universaltable(wlan_private * priv, u8 band); ++int lbs_set_universaltable(struct lbs_private *priv, u8 band); + +-int libertas_cmd_802_11d_domain_info(wlan_private * priv, ++int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, + struct cmd_ds_command *cmd, u16 cmdno, + u16 cmdOption); + +-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); +- +-int libertas_ret_802_11d_domain_info(wlan_private * priv, ++int lbs_ret_802_11d_domain_info(struct lbs_private *priv, + struct cmd_ds_command *resp); + + struct bss_descriptor; +-int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, ++int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, + struct bss_descriptor * bss); + +-int libertas_create_dnld_countryinfo_11d(wlan_private * priv); ++int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv); + +-#endif /* _WLAN_11D_ */ ++#endif +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/assoc.c linux-2.6.22-300/drivers/net/wireless/libertas/assoc.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/assoc.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/assoc.c 2008-06-05 18:10:06.000000000 -0400 +@@ -9,38 +9,16 @@ + #include "decl.h" + #include "hostcmd.h" + #include "host.h" ++#include "cmd.h" + + + static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +-static void print_assoc_req(const char * extra, struct assoc_request * assoc_req) +-{ +- lbs_deb_assoc( +- "#### Association Request: %s\n" +- " flags: 0x%08lX\n" +- " SSID: '%s'\n" +- " channel: %d\n" +- " band: %d\n" +- " mode: %d\n" +- " BSSID: " MAC_FMT "\n" +- " Encryption:%s%s%s\n" +- " auth: %d\n", +- extra, assoc_req->flags, +- escape_essid(assoc_req->ssid, assoc_req->ssid_len), +- assoc_req->channel, assoc_req->band, assoc_req->mode, +- MAC_ARG(assoc_req->bssid), +- assoc_req->secinfo.WPAenabled ? " WPA" : "", +- assoc_req->secinfo.WPA2enabled ? " WPA2" : "", +- assoc_req->secinfo.wep_enabled ? " WEP" : "", +- assoc_req->secinfo.auth_mode); +-} + +- +-static int assoc_helper_essid(wlan_private *priv, ++static int assoc_helper_essid(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct bss_descriptor * bss; + int channel = -1; +@@ -54,20 +32,17 @@ static int assoc_helper_essid(wlan_priva + if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) + channel = assoc_req->channel; + +- lbs_deb_assoc("New SSID requested: '%s'\n", ++ lbs_deb_assoc("SSID '%s' requested\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len)); + if (assoc_req->mode == IW_MODE_INFRA) { +- if (adapter->prescan) { +- libertas_send_specific_ssid_scan(priv, assoc_req->ssid, +- assoc_req->ssid_len, 0); +- } ++ lbs_send_specific_ssid_scan(priv, assoc_req->ssid, ++ assoc_req->ssid_len, 0); + +- bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid, ++ bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, + assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); + if (bss != NULL) { +- lbs_deb_assoc("SSID found in scan list, associating\n"); + memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); +- ret = wlan_associate(priv, assoc_req); ++ ret = lbs_associate(priv, assoc_req); + } else { + lbs_deb_assoc("SSID not found; cannot associate\n"); + } +@@ -75,23 +50,23 @@ static int assoc_helper_essid(wlan_priva + /* Scan for the network, do not save previous results. Stale + * scan data will cause us to join a non-existant adhoc network + */ +- libertas_send_specific_ssid_scan(priv, assoc_req->ssid, ++ lbs_send_specific_ssid_scan(priv, assoc_req->ssid, + assoc_req->ssid_len, 1); + + /* Search for the requested SSID in the scan table */ +- bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid, ++ bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, + assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel); + if (bss != NULL) { + lbs_deb_assoc("SSID found, will join\n"); + memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); +- libertas_join_adhoc_network(priv, assoc_req); ++ lbs_join_adhoc_network(priv, assoc_req); + } else { + /* else send START command */ + lbs_deb_assoc("SSID not found, creating adhoc network\n"); + memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, + IW_ESSID_MAX_SIZE); + assoc_req->bss.ssid_len = assoc_req->ssid_len; +- libertas_start_adhoc_network(priv, assoc_req); ++ lbs_start_adhoc_network(priv, assoc_req); + } + } + +@@ -100,31 +75,31 @@ static int assoc_helper_essid(wlan_priva + } + + +-static int assoc_helper_bssid(wlan_private *priv, ++static int assoc_helper_bssid(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct bss_descriptor * bss; ++ DECLARE_MAC_BUF(mac); + +- lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT, +- MAC_ARG(assoc_req->bssid)); ++ lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s", ++ print_mac(mac, assoc_req->bssid)); + + /* Search for index position in list for requested MAC */ +- bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid, ++ bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, + assoc_req->mode); + if (bss == NULL) { +- lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, " +- "cannot associate.\n", MAC_ARG(assoc_req->bssid)); ++ lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " ++ "cannot associate.\n", print_mac(mac, assoc_req->bssid)); + goto out; + } + + memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); + if (assoc_req->mode == IW_MODE_INFRA) { +- ret = wlan_associate(priv, assoc_req); +- lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret); ++ ret = lbs_associate(priv, assoc_req); ++ lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); + } else if (assoc_req->mode == IW_MODE_ADHOC) { +- libertas_join_adhoc_network(priv, assoc_req); ++ lbs_join_adhoc_network(priv, assoc_req); + } + + out: +@@ -133,11 +108,13 @@ out: + } + + +-static int assoc_helper_associate(wlan_private *priv, ++static int assoc_helper_associate(struct lbs_private *priv, + struct assoc_request * assoc_req) + { + int ret = 0, done = 0; + ++ lbs_deb_enter(LBS_DEB_ASSOC); ++ + /* If we're given and 'any' BSSID, try associating based on SSID */ + + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { +@@ -145,44 +122,38 @@ static int assoc_helper_associate(wlan_p + && compare_ether_addr(bssid_off, assoc_req->bssid)) { + ret = assoc_helper_bssid(priv, assoc_req); + done = 1; +- if (ret) { +- lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret); +- } + } + } + + if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + ret = assoc_helper_essid(priv, assoc_req); +- if (ret) { +- lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret); +- } + } + ++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + + +-static int assoc_helper_mode(wlan_private *priv, ++static int assoc_helper_mode(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + + lbs_deb_enter(LBS_DEB_ASSOC); + +- if (assoc_req->mode == adapter->mode) ++ if (assoc_req->mode == priv->mode) + goto done; + + if (assoc_req->mode == IW_MODE_INFRA) { +- if (adapter->psstate != PS_STATE_FULL_POWER) +- libertas_ps_wakeup(priv, cmd_option_waitforrsp); +- adapter->psmode = wlan802_11powermodecam; ++ if (priv->psstate != PS_STATE_FULL_POWER) ++ lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); ++ priv->psmode = LBS802_11POWERMODECAM; + } + +- adapter->mode = assoc_req->mode; +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_snmp_mib, +- 0, cmd_option_waitforrsp, ++ priv->mode = assoc_req->mode; ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_SNMP_MIB, ++ 0, CMD_OPTION_WAITFORRSP, + OID_802_11_INFRASTRUCTURE_MODE, + /* Shoot me now */ (void *) (size_t) assoc_req->mode); + +@@ -192,57 +163,77 @@ done: + } + + +-static int update_channel(wlan_private * priv) ++int lbs_update_channel(struct lbs_private *priv) + { +- /* the channel in f/w could be out of sync, get the current channel */ +- return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, +- cmd_opt_802_11_rf_channel_get, +- cmd_option_waitforrsp, 0, NULL); ++ int ret; ++ ++ /* the channel in f/w could be out of sync; get the current channel */ ++ lbs_deb_enter(LBS_DEB_ASSOC); ++ ++ ret = lbs_get_channel(priv); ++ if (ret > 0) { ++ priv->curbssparams.channel = ret; ++ ret = 0; ++ } ++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); ++ return ret; + } + +-void libertas_sync_channel(struct work_struct *work) ++void lbs_sync_channel(struct work_struct *work) + { +- wlan_private *priv = container_of(work, wlan_private, sync_channel); ++ struct lbs_private *priv = container_of(work, struct lbs_private, ++ sync_channel); + +- if (update_channel(priv) != 0) ++ lbs_deb_enter(LBS_DEB_ASSOC); ++ if (lbs_update_channel(priv)) + lbs_pr_info("Channel synchronization failed."); ++ lbs_deb_leave(LBS_DEB_ASSOC); + } + +-static int assoc_helper_channel(wlan_private *priv, ++static int assoc_helper_channel(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + + lbs_deb_enter(LBS_DEB_ASSOC); + +- ret = update_channel(priv); +- if (ret < 0) { +- lbs_deb_assoc("ASSOC: channel: error getting channel."); ++ ret = lbs_update_channel(priv); ++ if (ret) { ++ lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); ++ goto done; + } + +- if (assoc_req->channel == adapter->curbssparams.channel) ++ if (assoc_req->channel == priv->curbssparams.channel) + goto done; + +- lbs_deb_assoc("ASSOC: channel: %d -> %d\n", +- adapter->curbssparams.channel, assoc_req->channel); +- +- ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, +- cmd_opt_802_11_rf_channel_set, +- cmd_option_waitforrsp, 0, &assoc_req->channel); +- if (ret < 0) { +- lbs_deb_assoc("ASSOC: channel: error setting channel."); ++ if (priv->mesh_dev) { ++ /* Change mesh channel first; 21.p21 firmware won't let ++ you change channel otherwise (even though it'll return ++ an error to this */ ++ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, ++ assoc_req->channel); + } + +- ret = update_channel(priv); +- if (ret < 0) { +- lbs_deb_assoc("ASSOC: channel: error getting channel."); ++ lbs_deb_assoc("ASSOC: channel: %d -> %d\n", ++ priv->curbssparams.channel, assoc_req->channel); ++ ++ ret = lbs_set_channel(priv, assoc_req->channel); ++ if (ret < 0) ++ lbs_deb_assoc("ASSOC: channel: error setting channel.\n"); ++ ++ /* FIXME: shouldn't need to grab the channel _again_ after setting ++ * it since the firmware is supposed to return the new channel, but ++ * whatever... */ ++ ret = lbs_update_channel(priv); ++ if (ret) { ++ lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); ++ goto done; + } + +- if (assoc_req->channel != adapter->curbssparams.channel) { +- lbs_deb_assoc("ASSOC: channel: failed to update channel to %d", ++ if (assoc_req->channel != priv->curbssparams.channel) { ++ lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", + assoc_req->channel); +- goto done; ++ goto restore_mesh; + } + + if ( assoc_req->secinfo.wep_enabled +@@ -255,18 +246,22 @@ static int assoc_helper_channel(wlan_pri + } + + /* Must restart/rejoin adhoc networks after channel change */ +- set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); ++ set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); + +-done: ++ restore_mesh: ++ if (priv->mesh_dev) ++ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, ++ priv->curbssparams.channel); ++ ++ done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + + +-static int assoc_helper_wep_keys(wlan_private *priv, ++static int assoc_helper_wep_keys(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int i; + int ret = 0; + +@@ -277,16 +272,16 @@ static int assoc_helper_wep_keys(wlan_pr + || assoc_req->wep_keys[1].len + || assoc_req->wep_keys[2].len + || assoc_req->wep_keys[3].len) { +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_set_wep, +- cmd_act_add, +- cmd_option_waitforrsp, ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_SET_WEP, ++ CMD_ACT_ADD, ++ CMD_OPTION_WAITFORRSP, + 0, assoc_req); + } else { +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_set_wep, +- cmd_act_remove, +- cmd_option_waitforrsp, ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_SET_WEP, ++ CMD_ACT_REMOVE, ++ CMD_OPTION_WAITFORRSP, + 0, NULL); + } + +@@ -295,45 +290,41 @@ static int assoc_helper_wep_keys(wlan_pr + + /* enable/disable the MAC's WEP packet filter */ + if (assoc_req->secinfo.wep_enabled) +- adapter->currentpacketfilter |= cmd_act_mac_wep_enable; ++ priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE; + else +- adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable; +- ret = libertas_set_mac_packet_filter(priv); +- if (ret) +- goto out; ++ priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE; ++ ++ lbs_set_mac_control(priv); + +- mutex_lock(&adapter->lock); ++ mutex_lock(&priv->lock); + +- /* Copy WEP keys into adapter wep key fields */ ++ /* Copy WEP keys into priv wep key fields */ + for (i = 0; i < 4; i++) { +- memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], +- sizeof(struct WLAN_802_11_KEY)); ++ memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i], ++ sizeof(struct enc_key)); + } +- adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; ++ priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx; + +- mutex_unlock(&adapter->lock); ++ mutex_unlock(&priv->lock); + + out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + +-static int assoc_helper_secinfo(wlan_private *priv, ++static int assoc_helper_secinfo(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + u32 do_wpa; + u32 rsn = 0; + + lbs_deb_enter(LBS_DEB_ASSOC); + +- memcpy(&adapter->secinfo, &assoc_req->secinfo, +- sizeof(struct wlan_802_11_security)); ++ memcpy(&priv->secinfo, &assoc_req->secinfo, ++ sizeof(struct lbs_802_11_security)); + +- ret = libertas_set_mac_packet_filter(priv); +- if (ret) +- goto out; ++ lbs_set_mac_control(priv); + + /* If RSN is already enabled, don't try to enable it again, since + * ENABLE_RSN resets internal state machines and will clobber the +@@ -341,13 +332,13 @@ static int assoc_helper_secinfo(wlan_pri + */ + + /* Get RSN enabled/disabled */ +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_enable_rsn, +- cmd_act_set, +- cmd_option_waitforrsp, ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_ENABLE_RSN, ++ CMD_ACT_GET, ++ CMD_OPTION_WAITFORRSP, + 0, &rsn); + if (ret) { +- lbs_deb_assoc("Failed to get RSN status: %d", ret); ++ lbs_deb_assoc("Failed to get RSN status: %d\n", ret); + goto out; + } + +@@ -358,10 +349,10 @@ static int assoc_helper_secinfo(wlan_pri + + /* Set RSN enabled/disabled */ + rsn = do_wpa; +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_enable_rsn, +- cmd_act_set, +- cmd_option_waitforrsp, ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_ENABLE_RSN, ++ CMD_ACT_SET, ++ CMD_OPTION_WAITFORRSP, + 0, &rsn); + + out: +@@ -370,38 +361,62 @@ out: + } + + +-static int assoc_helper_wpa_keys(wlan_private *priv, ++static int assoc_helper_wpa_keys(struct lbs_private *priv, + struct assoc_request * assoc_req) + { + int ret = 0; ++ unsigned int flags = assoc_req->flags; + + lbs_deb_enter(LBS_DEB_ASSOC); + +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_key_material, +- cmd_act_set, +- cmd_option_waitforrsp, +- 0, assoc_req); ++ /* Work around older firmware bug where WPA unicast and multicast ++ * keys must be set independently. Seen in SDIO parts with firmware ++ * version 5.0.11p0. ++ */ ++ ++ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ++ clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_KEY_MATERIAL, ++ CMD_ACT_SET, ++ CMD_OPTION_WAITFORRSP, ++ 0, assoc_req); ++ assoc_req->flags = flags; ++ } ++ ++ if (ret) ++ goto out; ++ ++ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { ++ clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); ++ ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_KEY_MATERIAL, ++ CMD_ACT_SET, ++ CMD_OPTION_WAITFORRSP, ++ 0, assoc_req); ++ assoc_req->flags = flags; ++ } + ++out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + + +-static int assoc_helper_wpa_ie(wlan_private *priv, ++static int assoc_helper_wpa_ie(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + + lbs_deb_enter(LBS_DEB_ASSOC); + + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { +- memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); +- adapter->wpa_ie_len = assoc_req->wpa_ie_len; ++ memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); ++ priv->wpa_ie_len = assoc_req->wpa_ie_len; + } else { +- memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN); +- adapter->wpa_ie_len = 0; ++ memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN); ++ priv->wpa_ie_len = 0; + } + + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); +@@ -409,55 +424,68 @@ static int assoc_helper_wpa_ie(wlan_priv + } + + +-static int should_deauth_infrastructure(wlan_adapter *adapter, ++static int should_deauth_infrastructure(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- if (adapter->connect_status != libertas_connected) ++ int ret = 0; ++ ++ lbs_deb_enter(LBS_DEB_ASSOC); ++ ++ if (priv->connect_status != LBS_CONNECTED) + return 0; + + if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { +- lbs_deb_assoc("Deauthenticating due to new SSID in " +- " configuration request.\n"); +- return 1; ++ lbs_deb_assoc("Deauthenticating due to new SSID\n"); ++ ret = 1; ++ goto out; + } + + if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { +- if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) { +- lbs_deb_assoc("Deauthenticating due to updated security " +- "info in configuration request.\n"); +- return 1; ++ if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) { ++ lbs_deb_assoc("Deauthenticating due to new security\n"); ++ ret = 1; ++ goto out; + } + } + + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { +- lbs_deb_assoc("Deauthenticating due to new BSSID in " +- " configuration request.\n"); +- return 1; ++ lbs_deb_assoc("Deauthenticating due to new BSSID\n"); ++ ret = 1; ++ goto out; + } + + if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { +- lbs_deb_assoc("Deauthenticating due to channel switch.\n"); +- return 1; ++ lbs_deb_assoc("Deauthenticating due to channel switch\n"); ++ ret = 1; ++ goto out; + } + + /* FIXME: deal with 'auto' mode somehow */ + if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { +- if (assoc_req->mode != IW_MODE_INFRA) +- return 1; ++ if (assoc_req->mode != IW_MODE_INFRA) { ++ lbs_deb_assoc("Deauthenticating due to leaving " ++ "infra mode\n"); ++ ret = 1; ++ goto out; ++ } + } + +- return 0; ++out: ++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); ++ return ret; + } + + +-static int should_stop_adhoc(wlan_adapter *adapter, ++static int should_stop_adhoc(struct lbs_private *priv, + struct assoc_request * assoc_req) + { +- if (adapter->connect_status != libertas_connected) ++ lbs_deb_enter(LBS_DEB_ASSOC); ++ ++ if (priv->connect_status != LBS_CONNECTED) + return 0; + +- if (libertas_ssid_cmp(adapter->curbssparams.ssid, +- adapter->curbssparams.ssid_len, ++ if (lbs_ssid_cmp(priv->curbssparams.ssid, ++ priv->curbssparams.ssid_len, + assoc_req->ssid, assoc_req->ssid_len) != 0) + return 1; + +@@ -468,34 +496,53 @@ static int should_stop_adhoc(wlan_adapte + } + + if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { +- if (assoc_req->channel != adapter->curbssparams.channel) ++ if (assoc_req->channel != priv->curbssparams.channel) + return 1; + } + ++ lbs_deb_leave(LBS_DEB_ASSOC); + return 0; + } + + +-void libertas_association_worker(struct work_struct *work) ++void lbs_association_worker(struct work_struct *work) + { +- wlan_private *priv = container_of(work, wlan_private, assoc_work.work); +- wlan_adapter *adapter = priv->adapter; ++ struct lbs_private *priv = container_of(work, struct lbs_private, ++ assoc_work.work); + struct assoc_request * assoc_req = NULL; + int ret = 0; + int find_any_ssid = 0; ++ DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_ASSOC); + +- mutex_lock(&adapter->lock); +- assoc_req = adapter->pending_assoc_req; +- adapter->pending_assoc_req = NULL; +- adapter->in_progress_assoc_req = assoc_req; +- mutex_unlock(&adapter->lock); ++ mutex_lock(&priv->lock); ++ assoc_req = priv->pending_assoc_req; ++ priv->pending_assoc_req = NULL; ++ priv->in_progress_assoc_req = assoc_req; ++ mutex_unlock(&priv->lock); + + if (!assoc_req) + goto done; + +- print_assoc_req(__func__, assoc_req); ++ lbs_deb_assoc( ++ "Association Request:\n" ++ " flags: 0x%08lx\n" ++ " SSID: '%s'\n" ++ " chann: %d\n" ++ " band: %d\n" ++ " mode: %d\n" ++ " BSSID: %s\n" ++ " secinfo: %s%s%s\n" ++ " auth_mode: %d\n", ++ assoc_req->flags, ++ escape_essid(assoc_req->ssid, assoc_req->ssid_len), ++ assoc_req->channel, assoc_req->band, assoc_req->mode, ++ print_mac(mac, assoc_req->bssid), ++ assoc_req->secinfo.WPAenabled ? " WPA" : "", ++ assoc_req->secinfo.WPA2enabled ? " WPA2" : "", ++ assoc_req->secinfo.wep_enabled ? " WEP" : "", ++ assoc_req->secinfo.auth_mode); + + /* If 'any' SSID was specified, find an SSID to associate with */ + if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) +@@ -512,7 +559,7 @@ void libertas_association_worker(struct + if (find_any_ssid) { + u8 new_mode; + +- ret = libertas_find_best_network_ssid(priv, assoc_req->ssid, ++ ret = lbs_find_best_network_ssid(priv, assoc_req->ssid, + &assoc_req->ssid_len, assoc_req->mode, &new_mode); + if (ret) { + lbs_deb_assoc("Could not find best network\n"); +@@ -531,18 +578,18 @@ void libertas_association_worker(struct + * Check if the attributes being changing require deauthentication + * from the currently associated infrastructure access point. + */ +- if (adapter->mode == IW_MODE_INFRA) { +- if (should_deauth_infrastructure(adapter, assoc_req)) { +- ret = libertas_send_deauthentication(priv); ++ if (priv->mode == IW_MODE_INFRA) { ++ if (should_deauth_infrastructure(priv, assoc_req)) { ++ ret = lbs_send_deauthentication(priv); + if (ret) { + lbs_deb_assoc("Deauthentication due to new " + "configuration request failed: %d\n", + ret); + } + } +- } else if (adapter->mode == IW_MODE_ADHOC) { +- if (should_stop_adhoc(adapter, assoc_req)) { +- ret = libertas_stop_adhoc_network(priv); ++ } else if (priv->mode == IW_MODE_ADHOC) { ++ if (should_stop_adhoc(priv, assoc_req)) { ++ ret = lbs_stop_adhoc_network(priv); + if (ret) { + lbs_deb_assoc("Teardown of AdHoc network due to " + "new configuration request failed: %d\n", +@@ -555,53 +602,40 @@ void libertas_association_worker(struct + /* Send the various configuration bits to the firmware */ + if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { + ret = assoc_helper_mode(priv, assoc_req); +- if (ret) { +-lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); ++ if (ret) + goto out; +- } + } + + if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { + ret = assoc_helper_channel(priv, assoc_req); +- if (ret) { +- lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n", +- __LINE__, ret); ++ if (ret) + goto out; +- } + } + + if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { + ret = assoc_helper_wep_keys(priv, assoc_req); +- if (ret) { +-lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); ++ if (ret) + goto out; +- } + } + + if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { + ret = assoc_helper_secinfo(priv, assoc_req); +- if (ret) { +-lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); ++ if (ret) + goto out; +- } + } + + if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { + ret = assoc_helper_wpa_ie(priv, assoc_req); +- if (ret) { +-lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); ++ if (ret) + goto out; +- } + } + + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + ret = assoc_helper_wpa_keys(priv, assoc_req); +- if (ret) { +-lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret); ++ if (ret) + goto out; +- } + } + + /* SSID/BSSID should be the _last_ config option set, because they +@@ -613,30 +647,29 @@ lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret + + ret = assoc_helper_associate(priv, assoc_req); + if (ret) { +- lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n", ++ lbs_deb_assoc("ASSOC: association unsuccessful: %d\n", + ret); + success = 0; + } + +- if (adapter->connect_status != libertas_connected) { +- lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, " +- "not connected.\n"); ++ if (priv->connect_status != LBS_CONNECTED) { ++ lbs_deb_assoc("ASSOC: association unsuccessful, " ++ "not connected\n"); + success = 0; + } + + if (success) { +- lbs_deb_assoc("ASSOC: association attempt successful. " +- "Associated to '%s' (" MAC_FMT ")\n", +- escape_essid(adapter->curbssparams.ssid, +- adapter->curbssparams.ssid_len), +- MAC_ARG(adapter->curbssparams.bssid)); +- libertas_prepare_and_send_command(priv, +- cmd_802_11_rssi, +- 0, cmd_option_waitforrsp, 0, NULL); +- +- libertas_prepare_and_send_command(priv, +- cmd_802_11_get_log, +- 0, cmd_option_waitforrsp, 0, NULL); ++ lbs_deb_assoc("ASSOC: associated to '%s', %s\n", ++ escape_essid(priv->curbssparams.ssid, ++ priv->curbssparams.ssid_len), ++ print_mac(mac, priv->curbssparams.bssid)); ++ lbs_prepare_and_send_command(priv, ++ CMD_802_11_RSSI, ++ 0, CMD_OPTION_WAITFORRSP, 0, NULL); ++ ++ lbs_prepare_and_send_command(priv, ++ CMD_802_11_GET_LOG, ++ 0, CMD_OPTION_WAITFORRSP, 0, NULL); + } else { + ret = -1; + } +@@ -648,9 +681,9 @@ out: + ret); + } + +- mutex_lock(&adapter->lock); +- adapter->in_progress_assoc_req = NULL; +- mutex_unlock(&adapter->lock); ++ mutex_lock(&priv->lock); ++ priv->in_progress_assoc_req = NULL; ++ mutex_unlock(&priv->lock); + kfree(assoc_req); + + done: +@@ -661,14 +694,15 @@ done: + /* + * Caller MUST hold any necessary locks + */ +-struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) ++struct assoc_request *lbs_get_association_request(struct lbs_private *priv) + { + struct assoc_request * assoc_req; + +- if (!adapter->pending_assoc_req) { +- adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request), ++ lbs_deb_enter(LBS_DEB_ASSOC); ++ if (!priv->pending_assoc_req) { ++ priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request), + GFP_KERNEL); +- if (!adapter->pending_assoc_req) { ++ if (!priv->pending_assoc_req) { + lbs_pr_info("Not enough memory to allocate association" + " request!\n"); + return NULL; +@@ -678,60 +712,59 @@ struct assoc_request * wlan_get_associat + /* Copy current configuration attributes to the association request, + * but don't overwrite any that are already set. + */ +- assoc_req = adapter->pending_assoc_req; ++ assoc_req = priv->pending_assoc_req; + if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { +- memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid, ++ memcpy(&assoc_req->ssid, &priv->curbssparams.ssid, + IW_ESSID_MAX_SIZE); +- assoc_req->ssid_len = adapter->curbssparams.ssid_len; ++ assoc_req->ssid_len = priv->curbssparams.ssid_len; + } + + if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) +- assoc_req->channel = adapter->curbssparams.channel; ++ assoc_req->channel = priv->curbssparams.channel; + + if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags)) +- assoc_req->band = adapter->curbssparams.band; ++ assoc_req->band = priv->curbssparams.band; + + if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) +- assoc_req->mode = adapter->mode; ++ assoc_req->mode = priv->mode; + + if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { +- memcpy(&assoc_req->bssid, adapter->curbssparams.bssid, ++ memcpy(&assoc_req->bssid, priv->curbssparams.bssid, + ETH_ALEN); + } + + if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { + int i; + for (i = 0; i < 4; i++) { +- memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], +- sizeof(struct WLAN_802_11_KEY)); ++ memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i], ++ sizeof(struct enc_key)); + } + } + + if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) +- assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx; ++ assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx; + + if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { +- memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, +- sizeof(struct WLAN_802_11_KEY)); ++ memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key, ++ sizeof(struct enc_key)); + } + + if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { +- memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, +- sizeof(struct WLAN_802_11_KEY)); ++ memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key, ++ sizeof(struct enc_key)); + } + + if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { +- memcpy(&assoc_req->secinfo, &adapter->secinfo, +- sizeof(struct wlan_802_11_security)); ++ memcpy(&assoc_req->secinfo, &priv->secinfo, ++ sizeof(struct lbs_802_11_security)); + } + + if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { +- memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie, ++ memcpy(&assoc_req->wpa_ie, &priv->wpa_ie, + MAX_WPA_IE_LEN); +- assoc_req->wpa_ie_len = adapter->wpa_ie_len; ++ assoc_req->wpa_ie_len = priv->wpa_ie_len; + } + +- print_assoc_req(__func__, assoc_req); +- ++ lbs_deb_leave(LBS_DEB_ASSOC); + return assoc_req; + } +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/assoc.h linux-2.6.22-300/drivers/net/wireless/libertas/assoc.h +--- linux-2.6.22-250/drivers/net/wireless/libertas/assoc.h 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/assoc.h 2008-06-05 18:10:06.000000000 -0400 +@@ -1,32 +1,12 @@ + /* Copyright (C) 2006, Red Hat, Inc. */ + +-#ifndef _WLAN_ASSOC_H_ +-#define _WLAN_ASSOC_H_ ++#ifndef _LBS_ASSOC_H_ ++#define _LBS_ASSOC_H_ + + #include "dev.h" + +-void libertas_association_worker(struct work_struct *work); ++void lbs_association_worker(struct work_struct *work); ++struct assoc_request *lbs_get_association_request(struct lbs_private *priv); ++void lbs_sync_channel(struct work_struct *work); + +-struct assoc_request * wlan_get_association_request(wlan_adapter *adapter); +- +-void libertas_sync_channel(struct work_struct *work); +- +-#define ASSOC_DELAY (HZ / 2) +-static inline void wlan_postpone_association_work(wlan_private *priv) +-{ +- if (priv->adapter->surpriseremoved) +- return; +- cancel_delayed_work(&priv->assoc_work); +- queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); +-} +- +-static inline void wlan_cancel_association_work(wlan_private *priv) +-{ +- cancel_delayed_work(&priv->assoc_work); +- if (priv->adapter->pending_assoc_req) { +- kfree(priv->adapter->pending_assoc_req); +- priv->adapter->pending_assoc_req = NULL; +- } +-} +- +-#endif /* _WLAN_ASSOC_H */ ++#endif /* _LBS_ASSOC_H */ +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/cmd.c linux-2.6.22-300/drivers/net/wireless/libertas/cmd.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/cmd.c 2008-07-17 00:17:57.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/cmd.c 2008-06-05 18:10:06.000000000 -0400 +@@ -4,6 +4,7 @@ + */ + + #include ++#include + #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 + #include + #include ++#include + #include + + #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 + + #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 + +@@ -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 + #include + #include + #include +-#include + + #include "defs.h" + #include "scan.h" +-#include "thread.h" + +-extern struct ethtool_ops libertas_ethtool_ops; ++extern struct ethtool_ops lbs_ethtool_ops; + + #define MAX_BSSID_PER_CHANNEL 16 + +@@ -54,7 +52,7 @@ struct region_channel { + struct chan_freq_power *CFP; + }; + +-struct wlan_802_11_security { ++struct lbs_802_11_security { + u8 WPAenabled; + u8 WPA2enabled; + u8 wep_enabled; +@@ -73,10 +71,8 @@ struct current_bss_params { + u8 band; + /** channel */ + u8 channel; +- /** number of rates supported */ +- int numofrates; +- /** supported rates*/ +- u8 datarates[WLAN_SUPPORTED_RATES]; ++ /** zero-terminated array of supported data rates */ ++ u8 rates[MAX_RATES + 1]; + }; + + /** sleep_params */ +@@ -90,7 +86,7 @@ struct sleep_params { + }; + + /* Mesh statistics */ +-struct wlan_mesh_stats { ++struct lbs_mesh_stats { + u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ + u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ + u32 fwd_drop_ttl; /* Fwd: TTL zero */ +@@ -102,22 +98,23 @@ struct wlan_mesh_stats { + }; + + /** Private structure for the MV device */ +-struct _wlan_private { +- int open; ++struct lbs_private { + int mesh_open; + int infra_open; ++ int mesh_autostart_enabled; ++ __le16 boot2_version; + + char name[DEV_NAME_LEN]; + + void *card; +- wlan_adapter *adapter; + struct net_device *dev; + + struct net_device_stats stats; +- struct net_device *mesh_dev ; /* Virtual device */ ++ struct net_device *mesh_dev; /* Virtual device */ ++ struct net_device *rtap_net_dev; + + struct iw_statistics wstats; +- struct wlan_mesh_stats mstats; ++ struct lbs_mesh_stats mstats; + struct dentry *debugfs_dir; + struct dentry *debugfs_debug; + struct dentry *debugfs_files[6]; +@@ -135,78 +132,37 @@ struct _wlan_private { + /** Upload length */ + u32 upld_len; + /* Upload buffer */ +- u8 upld_buf[WLAN_UPLD_SIZE]; ++ u8 upld_buf[LBS_UPLD_SIZE]; + /* Download sent: + bit0 1/0=data_sent/data_tx_done, + bit1 1/0=cmd_sent/cmd_tx_done, + all other bits reserved 0 */ + u8 dnld_sent; + +- const struct firmware *firmware; +- struct device *hotplug_device; +- + /** thread to service interrupts */ +- struct wlan_thread mainthread; ++ struct task_struct *main_thread; ++ wait_queue_head_t waitq; ++ struct workqueue_struct *work_thread; ++ ++ struct work_struct mcast_work; + ++ struct delayed_work scan_work; + struct delayed_work assoc_work; +- struct workqueue_struct *assoc_thread; + struct work_struct sync_channel; + + /** Hardware access */ +- int (*hw_register_dev) (wlan_private * priv); +- int (*hw_unregister_dev) (wlan_private *); +- int (*hw_prog_firmware) (wlan_private *); +- int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb); +- int (*hw_get_int_status) (wlan_private * priv, u8 *); +- int (*hw_read_event_cause) (wlan_private *); +-}; +- +-/** Association request +- * +- * Encapsulates all the options that describe a specific assocation request +- * or configuration of the wireless card's radio, mode, and security settings. +- */ +-struct assoc_request { +-#define ASSOC_FLAG_SSID 1 +-#define ASSOC_FLAG_CHANNEL 2 +-#define ASSOC_FLAG_BAND 3 +-#define ASSOC_FLAG_MODE 4 +-#define ASSOC_FLAG_BSSID 5 +-#define ASSOC_FLAG_WEP_KEYS 6 +-#define ASSOC_FLAG_WEP_TX_KEYIDX 7 +-#define ASSOC_FLAG_WPA_MCAST_KEY 8 +-#define ASSOC_FLAG_WPA_UCAST_KEY 9 +-#define ASSOC_FLAG_SECINFO 10 +-#define ASSOC_FLAG_WPA_IE 11 +- unsigned long flags; +- +- u8 ssid[IW_ESSID_MAX_SIZE + 1]; +- u8 ssid_len; +- u8 channel; +- u8 band; +- u8 mode; +- u8 bssid[ETH_ALEN]; ++ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); ++ int (*hw_get_int_status) (struct lbs_private *priv, u8 *); ++ int (*hw_read_event_cause) (struct lbs_private *); ++ ++ /* Wake On LAN */ ++ uint32_t wol_criteria; ++ uint8_t wol_gpio; ++ uint8_t wol_gap; + +- /** WEP keys */ +- struct WLAN_802_11_KEY wep_keys[4]; +- u16 wep_tx_keyidx; +- +- /** WPA keys */ +- struct WLAN_802_11_KEY wpa_mcast_key; +- struct WLAN_802_11_KEY wpa_unicast_key; +- +- struct wlan_802_11_security secinfo; ++ /* was struct lbs_adapter from here... */ + +- /** WPA Information Elements*/ +- u8 wpa_ie[MAX_WPA_IE_LEN]; +- u8 wpa_ie_len; +- +- /* BSS to associate with for infrastructure of Ad-Hoc join */ +- struct bss_descriptor bss; +-}; +- +-/** Wlan adapter data structure*/ +-struct _wlan_adapter { ++ /** Wlan adapter data structure*/ + /** STATUS variables */ + u8 fwreleasenumber[4]; + u32 fwcapinfo; +@@ -214,7 +170,10 @@ struct _wlan_adapter { + + struct mutex lock; + +- u8 tmptxbuf[WLAN_UPLD_SIZE]; ++ /* TX packet ready to be sent... */ ++ int tx_pending_len; /* -1 while building packet */ ++ ++ u8 tx_pending_buf[LBS_UPLD_SIZE]; + /* protected by hard_start_xmit serialization */ + + /** command-related variables */ +@@ -232,8 +191,7 @@ struct _wlan_adapter { + struct list_head cmdpendingq; + + wait_queue_head_t cmd_pending; +- u8 nr_cmd_pending; +- /* command related variables protected by adapter->driver_lock */ ++ /* command related variables protected by priv->driver_lock */ + + /** Async and Sync Event variables */ + u32 intcounter; +@@ -245,37 +203,32 @@ struct _wlan_adapter { + + /** Timers */ + struct timer_list command_timer; +- +- /* TX queue used in PS mode */ +- spinlock_t txqueue_lock; +- struct sk_buff *tx_queue_ps[NR_TX_QUEUE]; +- unsigned int tx_queue_idx; ++ int nr_retries; ++ int cmd_timed_out; + + u8 hisregcpy; + + /** current ssid/bssid related parameters*/ + struct current_bss_params curbssparams; + ++ uint16_t mesh_tlv; ++ u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 mesh_ssid_len; ++ + /* IW_MODE_* */ + u8 mode; + +- u8 prev_ssid[IW_ESSID_MAX_SIZE + 1]; +- u8 prev_ssid_len; +- u8 prev_bssid[ETH_ALEN]; +- + /* Scan results list */ + struct list_head network_list; + struct list_head network_free_list; + struct bss_descriptor *networks; + +- u8 scantype; +- u32 scanmode; +- +- u16 beaconperiod; ++ u16 beacon_period; ++ u8 beacon_enable; + u8 adhoccreate; + + /** capability Info used in Association, start, join */ +- struct ieeetypes_capinfo capinfo; ++ u16 capability; + + /** MAC address information */ + u8 current_addr[ETH_ALEN]; +@@ -287,71 +240,53 @@ struct _wlan_adapter { + + u16 enablehwauto; + u16 ratebitmap; +- /** control G rates */ +- u8 adhoc_grate_enabled; +- +- u32 txantenna; +- u32 rxantenna; + + u32 fragthsd; + u32 rtsthsd; + +- u32 datarate; +- u8 is_datarate_auto; +- +- u16 listeninterval; +- u16 prescan; + u8 txretrycount; + + /** Tx-related variables (for single packet tx) */ + struct sk_buff *currenttxskb; +- u16 TxLockFlag; + + /** NIC Operation characteristics */ +- u16 currentpacketfilter; ++ u16 mac_control; + u32 connect_status; ++ u32 mesh_connect_status; + u16 regioncode; +- u16 regiontableindex; + u16 txpowerlevel; + + /** POWER MANAGEMENT AND PnP SUPPORT */ + u8 surpriseremoved; +- u16 atimwindow; + + u16 psmode; /* Wlan802_11PowermodeCAM=disable + Wlan802_11PowermodeMAX_PSP=enable */ +- u16 multipledtim; + u32 psstate; ++ char ps_supported; + u8 needtowakeup; + +- struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; +- u16 locallisteninterval; +- u16 nullpktinterval; ++ struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep; ++ struct cmd_header lbs_ps_confirm_wake; + + struct assoc_request * pending_assoc_req; + struct assoc_request * in_progress_assoc_req; + + /** Encryption parameter */ +- struct wlan_802_11_security secinfo; ++ struct lbs_802_11_security secinfo; + + /** WEP keys */ +- struct WLAN_802_11_KEY wep_keys[4]; ++ struct enc_key wep_keys[4]; + u16 wep_tx_keyidx; + + /** WPA keys */ +- struct WLAN_802_11_KEY wpa_mcast_key; +- struct WLAN_802_11_KEY wpa_unicast_key; ++ struct enc_key wpa_mcast_key; ++ struct enc_key wpa_unicast_key; + + /** WPA Information Elements*/ + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; + +- u16 rxantennamode; +- u16 txantennamode; +- + /** Requested Signal Strength*/ +- u16 bcn_avg_factor; +- u16 data_avg_factor; + u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; + u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; + u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; +@@ -359,15 +294,13 @@ struct _wlan_adapter { + u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; + u16 nextSNRNF; + u16 numSNRNF; +- u16 rxpd_rate; + + u8 radioon; + u32 preamble; + +- /** Multi bands Parameter*/ +- u8 libertas_supported_rates[G_SUPPORTED_RATES]; +- +- /** Blue Tooth Co-existence Arbitration */ ++ /** data rate stuff */ ++ u8 cur_rate; ++ u8 auto_rate; + + /** sleep_params */ + struct sleep_params sp; +@@ -381,7 +314,7 @@ struct _wlan_adapter { + struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; + + /** 11D and Domain Regulatory Data */ +- struct wlan_802_11d_domain_reg domainreg; ++ struct lbs_802_11d_domain_reg domainreg; + struct parsed_region_chan_11d parsed_region_chan; + + /** FSM variable for 11d support */ +@@ -389,20 +322,57 @@ struct _wlan_adapter { + + /** MISCELLANEOUS */ + u8 *prdeeprom; +- struct wlan_offset_value offsetvalue; ++ struct lbs_offset_value offsetvalue; + + struct cmd_ds_802_11_get_log logmsg; +- u16 scanprobes; +- +- u32 pkttxctrl; + +- u16 txrate; +- u32 linkmode; +- u32 radiomode; +- u32 debugmode; ++ u32 monitormode; ++ int last_scanned_channel; + u8 fw_ready; ++}; + +- u8 last_scanned_channel; ++/** Association request ++ * ++ * Encapsulates all the options that describe a specific assocation request ++ * or configuration of the wireless card's radio, mode, and security settings. ++ */ ++struct assoc_request { ++#define ASSOC_FLAG_SSID 1 ++#define ASSOC_FLAG_CHANNEL 2 ++#define ASSOC_FLAG_BAND 3 ++#define ASSOC_FLAG_MODE 4 ++#define ASSOC_FLAG_BSSID 5 ++#define ASSOC_FLAG_WEP_KEYS 6 ++#define ASSOC_FLAG_WEP_TX_KEYIDX 7 ++#define ASSOC_FLAG_WPA_MCAST_KEY 8 ++#define ASSOC_FLAG_WPA_UCAST_KEY 9 ++#define ASSOC_FLAG_SECINFO 10 ++#define ASSOC_FLAG_WPA_IE 11 ++ unsigned long flags; ++ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++ u8 channel; ++ u8 band; ++ u8 mode; ++ u8 bssid[ETH_ALEN]; ++ ++ /** WEP keys */ ++ struct enc_key wep_keys[4]; ++ u16 wep_tx_keyidx; ++ ++ /** WPA keys */ ++ struct enc_key wpa_mcast_key; ++ struct enc_key wpa_unicast_key; ++ ++ struct lbs_802_11_security secinfo; ++ ++ /** WPA Information Elements*/ ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ u8 wpa_ie_len; ++ ++ /* BSS to associate with for infrastructure of Ad-Hoc join */ ++ struct bss_descriptor bss; + }; + +-#endif /* _WLAN_DEV_H_ */ ++#endif +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/ethtool.c linux-2.6.22-300/drivers/net/wireless/libertas/ethtool.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/ethtool.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/ethtool.c 2008-06-05 18:10:06.000000000 -0400 +@@ -8,6 +8,8 @@ + #include "dev.h" + #include "join.h" + #include "wext.h" ++#include "cmd.h" ++ + static const char * mesh_stat_strings[]= { + "drop_duplicate_bcast", + "drop_ttl_zero", +@@ -19,35 +21,34 @@ static const char * mesh_stat_strings[]= + "tx_failed_cnt" + }; + +-static void libertas_ethtool_get_drvinfo(struct net_device *dev, ++static void lbs_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) + { +- wlan_private *priv = (wlan_private *) dev->priv; ++ struct lbs_private *priv = (struct lbs_private *) dev->priv; + char fwver[32]; + +- libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1); ++ lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1); + + strcpy(info->driver, "libertas"); +- strcpy(info->version, libertas_driver_version); ++ strcpy(info->version, lbs_driver_version); + strcpy(info->fw_version, fwver); + } + + /* All 8388 parts have 16KiB EEPROM size at the time of writing. + * In case that changes this needs fixing. + */ +-#define LIBERTAS_EEPROM_LEN 16384 ++#define LBS_EEPROM_LEN 16384 + +-static int libertas_ethtool_get_eeprom_len(struct net_device *dev) ++static int lbs_ethtool_get_eeprom_len(struct net_device *dev) + { +- return LIBERTAS_EEPROM_LEN; ++ return LBS_EEPROM_LEN; + } + +-static int libertas_ethtool_get_eeprom(struct net_device *dev, ++static int lbs_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 * bytes) + { +- wlan_private *priv = (wlan_private *) dev->priv; +- wlan_adapter *adapter = priv->adapter; +- struct wlan_ioctl_regrdwr regctrl; ++ struct lbs_private *priv = (struct lbs_private *) dev->priv; ++ struct lbs_ioctl_regrdwr regctrl; + char *ptr; + int ret; + +@@ -55,48 +56,47 @@ static int libertas_ethtool_get_eeprom(s + regctrl.offset = eeprom->offset; + regctrl.NOB = eeprom->len; + +- if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN) ++ if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN) + return -EINVAL; + + // mutex_lock(&priv->mutex); + +- adapter->prdeeprom = +- (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); +- if (!adapter->prdeeprom) ++ priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); ++ if (!priv->prdeeprom) + return -ENOMEM; +- memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); ++ memcpy(priv->prdeeprom, ®ctrl, sizeof(regctrl)); + + /* +14 is for action, offset, and NOB in + * response */ + lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n", + regctrl.action, regctrl.offset, regctrl.NOB); + +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_eeprom_access, ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_EEPROM_ACCESS, + regctrl.action, +- cmd_option_waitforrsp, 0, ++ CMD_OPTION_WAITFORRSP, 0, + ®ctrl); + + if (ret) { +- if (adapter->prdeeprom) +- kfree(adapter->prdeeprom); ++ if (priv->prdeeprom) ++ kfree(priv->prdeeprom); + goto done; + } + + mdelay(10); + +- ptr = (char *)adapter->prdeeprom; ++ ptr = (char *)priv->prdeeprom; + + /* skip the command header, but include the "value" u32 variable */ +- ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4; ++ ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4; + + /* + * Return the result back to the user + */ + memcpy(bytes, ptr, eeprom->len); + +- if (adapter->prdeeprom) +- kfree(adapter->prdeeprom); ++ if (priv->prdeeprom) ++ kfree(priv->prdeeprom); + // mutex_unlock(&priv->mutex); + + ret = 0; +@@ -106,65 +106,56 @@ done: + return ret; + } + +-static void libertas_ethtool_get_stats(struct net_device * dev, +- struct ethtool_stats * stats, u64 * data) ++static void lbs_ethtool_get_stats(struct net_device *dev, ++ struct ethtool_stats *stats, uint64_t *data) + { +- wlan_private *priv = dev->priv; +- +- lbs_deb_enter(LBS_DEB_ETHTOOL); +- +- stats->cmd = ETHTOOL_GSTATS; +- BUG_ON(stats->n_stats != MESH_STATS_NUM); +- +- data[0] = priv->mstats.fwd_drop_rbt; +- data[1] = priv->mstats.fwd_drop_ttl; +- data[2] = priv->mstats.fwd_drop_noroute; +- data[3] = priv->mstats.fwd_drop_nobuf; +- data[4] = priv->mstats.fwd_unicast_cnt; +- data[5] = priv->mstats.fwd_bcast_cnt; +- data[6] = priv->mstats.drop_blind; +- data[7] = priv->mstats.tx_failed_cnt; +- +- lbs_deb_enter(LBS_DEB_ETHTOOL); +-} +- +-static int libertas_ethtool_get_stats_count(struct net_device * dev) +-{ +- int ret; +- wlan_private *priv = dev->priv; ++ struct lbs_private *priv = dev->priv; + struct cmd_ds_mesh_access mesh_access; ++ int ret; + + lbs_deb_enter(LBS_DEB_ETHTOOL); + + /* Get Mesh Statistics */ +- ret = libertas_prepare_and_send_command(priv, +- cmd_mesh_access, cmd_act_mesh_get_stats, +- cmd_option_waitforrsp, 0, &mesh_access); ++ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access); + + if (ret) { +- ret = 0; +- goto done; ++ memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t))); ++ return; + } + +- priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); +- priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); +- priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); +- priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); +- priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); +- priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); +- priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); +- priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); ++ priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); ++ priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); ++ priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); ++ priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); ++ priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); ++ priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); ++ priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); ++ priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); ++ ++ data[0] = priv->mstats.fwd_drop_rbt; ++ data[1] = priv->mstats.fwd_drop_ttl; ++ data[2] = priv->mstats.fwd_drop_noroute; ++ data[3] = priv->mstats.fwd_drop_nobuf; ++ data[4] = priv->mstats.fwd_unicast_cnt; ++ data[5] = priv->mstats.fwd_bcast_cnt; ++ data[6] = priv->mstats.drop_blind; ++ data[7] = priv->mstats.tx_failed_cnt; + +- ret = MESH_STATS_NUM; ++ lbs_deb_enter(LBS_DEB_ETHTOOL); ++} + +-done: +- lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret); +- return ret; ++static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset) ++{ ++ struct lbs_private *priv = dev->priv; ++ ++ if (sset == ETH_SS_STATS && dev == priv->mesh_dev) ++ return MESH_STATS_NUM; ++ ++ return -EOPNOTSUPP; + } + +-static void libertas_ethtool_get_strings (struct net_device * dev, +- u32 stringset, +- u8 * s) ++static void lbs_ethtool_get_strings(struct net_device *dev, ++ uint32_t stringset, uint8_t *s) + { + int i; + +@@ -182,12 +173,57 @@ static void libertas_ethtool_get_strings + lbs_deb_enter(LBS_DEB_ETHTOOL); + } + +-struct ethtool_ops libertas_ethtool_ops = { +- .get_drvinfo = libertas_ethtool_get_drvinfo, +- .get_eeprom = libertas_ethtool_get_eeprom, +- .get_eeprom_len = libertas_ethtool_get_eeprom_len, +- .get_stats_count = libertas_ethtool_get_stats_count, +- .get_ethtool_stats = libertas_ethtool_get_stats, +- .get_strings = libertas_ethtool_get_strings, ++static void lbs_ethtool_get_wol(struct net_device *dev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct lbs_private *priv = dev->priv; ++ ++ if (priv->wol_criteria == 0xffffffff) { ++ /* Interface driver didn't configure wake */ ++ wol->supported = wol->wolopts = 0; ++ return; ++ } ++ ++ wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY; ++ ++ if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA) ++ wol->wolopts |= WAKE_UCAST; ++ if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA) ++ wol->wolopts |= WAKE_MCAST; ++ if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA) ++ wol->wolopts |= WAKE_BCAST; ++ if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT) ++ wol->wolopts |= WAKE_PHY; ++} ++ ++static int lbs_ethtool_set_wol(struct net_device *dev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct lbs_private *priv = dev->priv; ++ uint32_t criteria = 0; ++ ++ if (priv->wol_criteria == 0xffffffff && wol->wolopts) ++ return -EOPNOTSUPP; ++ ++ if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY)) ++ return -EOPNOTSUPP; ++ ++ if (wol->wolopts & WAKE_UCAST) criteria |= EHS_WAKE_ON_UNICAST_DATA; ++ if (wol->wolopts & WAKE_MCAST) criteria |= EHS_WAKE_ON_MULTICAST_DATA; ++ if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA; ++ if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT; ++ ++ return lbs_host_sleep_cfg(priv, criteria); ++} ++ ++struct ethtool_ops lbs_ethtool_ops = { ++ .get_drvinfo = lbs_ethtool_get_drvinfo, ++ .get_eeprom = lbs_ethtool_get_eeprom, ++ .get_eeprom_len = lbs_ethtool_get_eeprom_len, ++ .get_sset_count = lbs_ethtool_get_sset_count, ++ .get_ethtool_stats = lbs_ethtool_get_stats, ++ .get_strings = lbs_ethtool_get_strings, ++ .get_wol = lbs_ethtool_get_wol, ++ .set_wol = lbs_ethtool_set_wol, + }; + +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/fw.c linux-2.6.22-300/drivers/net/wireless/libertas/fw.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/fw.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/fw.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,349 +0,0 @@ +-/** +- * This file contains the initialization for FW and HW +- */ +-#include +- +-#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 + #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 +-#include +-#include +-#include +- +-#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 ++ ++ 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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define DRV_NAME "libertas_cs" ++ ++#include "decl.h" ++#include "defs.h" ++#include "dev.h" ++ ++ ++/********************************************************************/ ++/* Module stuff */ ++/********************************************************************/ ++ ++MODULE_AUTHOR("Holger Schurig "); ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + #include + #include +-#include + #include ++#include + + #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 ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++ ++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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "host.h" ++#include "radiotap.h" ++#include "decl.h" ++#include "defs.h" ++#include "dev.h" ++#include "join.h" ++#include "wext.h" ++#include "cmd.h" ++#include "ioctl.h" ++ ++#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ ++ IW_ESSID_MAX_SIZE + \ ++ IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ ++ IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ ++ IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ ++ ++#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) ++ ++static int lbs_set_region(struct lbs_private * priv, u16 region_code) ++{ ++ int i; ++ int ret = 0; ++ ++ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { ++ // use the region code to search for the index ++ if (region_code == lbs_region_code_to_index[i]) { ++ priv->regioncode = region_code; ++ break; ++ } ++ } ++ ++ // if it's unidentified region code ++ if (i >= MRVDRV_MAX_REGION_CODE) { ++ lbs_deb_ioctl("region Code not identified\n"); ++ ret = -1; ++ goto done; ++ } ++ ++ if (lbs_set_regiontable(priv, priv->regioncode, 0)) { ++ ret = -EINVAL; ++ } ++ ++done: ++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); ++ return ret; ++} ++ ++static inline int hex2int(char c) ++{ ++ if (c >= '0' && c <= '9') ++ return (c - '0'); ++ if (c >= 'a' && c <= 'f') ++ return (c - 'a' + 10); ++ if (c >= 'A' && c <= 'F') ++ return (c - 'A' + 10); ++ return -1; ++} ++ ++/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") ++ into binary format (6 bytes). ++ ++ This function expects that each byte is represented with 2 characters ++ (e.g., 11:2:11:11:11:11 is invalid) ++ ++ */ ++static char *eth_str2addr(char *ethstr, u8 * addr) ++{ ++ int i, val, val2; ++ char *pos = ethstr; ++ ++ /* get rid of initial blanks */ ++ while (*pos == ' ' || *pos == '\t') ++ ++pos; ++ ++ for (i = 0; i < 6; i++) { ++ val = hex2int(*pos++); ++ if (val < 0) ++ return NULL; ++ val2 = hex2int(*pos++); ++ if (val2 < 0) ++ return NULL; ++ addr[i] = (val * 16 + val2) & 0xff; ++ ++ if (i < 5 && *pos++ != ':') ++ return NULL; ++ } ++ return pos; ++} ++ ++/* this writes xx:xx:xx:xx:xx:xx into ethstr ++ (ethstr must have space for 18 chars) */ ++static int eth_addr2str(u8 * addr, char *ethstr) ++{ ++ int i; ++ char *pos = ethstr; ++ ++ for (i = 0; i < 6; i++) { ++ sprintf(pos, "%02x", addr[i] & 0xff); ++ pos += 2; ++ if (i < 5) ++ *pos++ = ':'; ++ } ++ return 17; ++} ++ ++/** ++ * @brief Add an entry to the BT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bt_add_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char ethaddrs_str[18]; ++ char *pos; ++ u8 ethaddr[ETH_ALEN]; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, ++ sizeof(ethaddrs_str))) ++ return -EFAULT; ++ ++ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { ++ lbs_pr_info("BT_ADD: Invalid MAC address\n"); ++ return -EINVAL; ++ } ++ ++ lbs_deb_ioctl("BT: adding %s\n", ethaddrs_str); ++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS, ++ CMD_ACT_BT_ACCESS_ADD, ++ CMD_OPTION_WAITFORRSP, 0, ethaddr); ++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); ++ return ret; ++} ++ ++/** ++ * @brief Delete an entry from the BT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bt_del_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char ethaddrs_str[18]; ++ u8 ethaddr[ETH_ALEN]; ++ char *pos; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, ++ sizeof(ethaddrs_str))) ++ return -EFAULT; ++ ++ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { ++ lbs_pr_info("Invalid MAC address\n"); ++ return -EINVAL; ++ } ++ ++ lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str); ++ ++ return (lbs_prepare_and_send_command(priv, ++ CMD_BT_ACCESS, ++ CMD_ACT_BT_ACCESS_DEL, ++ CMD_OPTION_WAITFORRSP, 0, ethaddr)); ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief Reset all entries from the BT table ++ * @param priv A pointer to struct lbs_private structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bt_reset_ioctl(struct lbs_private * priv) ++{ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ lbs_pr_alert( "BT: resetting\n"); ++ ++ return (lbs_prepare_and_send_command(priv, ++ CMD_BT_ACCESS, ++ CMD_ACT_BT_ACCESS_RESET, ++ CMD_OPTION_WAITFORRSP, 0, NULL)); ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief List an entry from the BT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bt_list_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ int pos; ++ char *addr1; ++ struct iwreq *wrq = (struct iwreq *)req; ++ /* used to pass id and store the bt entry returned by the FW */ ++ union { ++ u32 id; ++ char addr1addr2[2 * ETH_ALEN]; ++ } param; ++ static char outstr[64]; ++ char *pbuf = outstr; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { ++ lbs_deb_ioctl("Copy from user failed\n"); ++ return -1; ++ } ++ param.id = simple_strtoul(outstr, NULL, 10); ++ pos = sprintf(pbuf, "%d: ", param.id); ++ pbuf += pos; ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS, ++ CMD_ACT_BT_ACCESS_LIST, ++ CMD_OPTION_WAITFORRSP, 0, ++ (char *)¶m); ++ ++ if (ret == 0) { ++ addr1 = param.addr1addr2; ++ ++ pos = sprintf(pbuf, "BT includes node "); ++ pbuf += pos; ++ pos = eth_addr2str(addr1, pbuf); ++ pbuf += pos; ++ } else { ++ sprintf(pbuf, "(null)"); ++ pbuf += pos; ++ } ++ ++ wrq->u.data.length = strlen(outstr); ++ if (copy_to_user(wrq->u.data.pointer, (char *)outstr, ++ wrq->u.data.length)) { ++ lbs_deb_ioctl("BT_LIST: Copy to user failed!\n"); ++ return -EFAULT; ++ } ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0 ; ++} ++ ++/** ++ * @brief Sets inverted state of blacklist (non-zero if inverted) ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bt_set_invert_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ int ret; ++ struct iwreq *wrq = (struct iwreq *)req; ++ union { ++ u32 id; ++ char addr1addr2[2 * ETH_ALEN]; ++ } param; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ param.id = SUBCMD_DATA(wrq) ; ++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS, ++ CMD_ACT_BT_ACCESS_SET_INVERT, ++ CMD_OPTION_WAITFORRSP, 0, ++ (char *)¶m); ++ if (ret != 0) ++ return -EFAULT; ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief Gets inverted state of blacklist (non-zero if inverted) ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bt_get_invert_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ int ret; ++ union { ++ __le32 id; ++ char addr1addr2[2 * ETH_ALEN]; ++ } param; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS, ++ CMD_ACT_BT_ACCESS_GET_INVERT, ++ CMD_OPTION_WAITFORRSP, 0, ++ (char *)¶m); ++ ++ if (ret == 0) ++ wrq->u.param.value = le32_to_cpu(param.id); ++ else ++ return -EFAULT; ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief Find the next parameter in an input string ++ * @param ptr A pointer to the input parameter string ++ * @return A pointer to the next parameter, or 0 if no parameters left. ++ */ ++static char * next_param(char * ptr) ++{ ++ if (!ptr) return NULL; ++ while (*ptr == ' ' || *ptr == '\t') ++ptr; ++ return (*ptr == '\0') ? NULL : ptr; ++} ++ ++/** ++ * @brief Add an entry to the FWT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_add_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char in_str[128]; ++ static struct cmd_ds_fwt_access fwt_access; ++ char *ptr; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) ++ return -EFAULT; ++ ++ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { ++ lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); ++ return -EINVAL; ++ } ++ ++ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { ++ lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); ++ return -EINVAL; ++ } ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.metric = ++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ else ++ fwt_access.metric = cpu_to_le32(FWT_DEFAULT_METRIC); ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); ++ else ++ fwt_access.dir = FWT_DEFAULT_DIR; ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10); ++ else ++ fwt_access.rate = FWT_DEFAULT_RATE; ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.ssn = ++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ else ++ fwt_access.ssn = cpu_to_le32(FWT_DEFAULT_SSN); ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.dsn = ++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ else ++ fwt_access.dsn = cpu_to_le32(FWT_DEFAULT_DSN); ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); ++ else ++ fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); ++ else ++ fwt_access.ttl = FWT_DEFAULT_TTL; ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.expiration = ++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ else ++ fwt_access.expiration = cpu_to_le32(FWT_DEFAULT_EXPIRATION); ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); ++ else ++ fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.snr = ++ cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ else ++ fwt_access.snr = cpu_to_le32(FWT_DEFAULT_SNR); ++ ++#ifdef DEBUG ++ { ++ char ethaddr1_str[18], ethaddr2_str[18]; ++ eth_addr2str(fwt_access.da, ethaddr1_str); ++ eth_addr2str(fwt_access.ra, ethaddr2_str); ++ lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, ++ fwt_access.dir, ethaddr2_str); ++ lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", ++ fwt_access.ssn, fwt_access.dsn, fwt_access.metric, ++ fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, ++ fwt_access.sleepmode, fwt_access.snr); ++ } ++#endif ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_ADD, ++ CMD_OPTION_WAITFORRSP, 0, ++ (void *)&fwt_access); ++ ++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); ++ return ret; ++} ++ ++/** ++ * @brief Delete an entry from the FWT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_del_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char in_str[64]; ++ static struct cmd_ds_fwt_access fwt_access; ++ char *ptr; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) ++ return -EFAULT; ++ ++ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { ++ lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); ++ return -EINVAL; ++ } ++ ++ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { ++ lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); ++ return -EINVAL; ++ } ++ ++ if ((ptr = next_param(ptr))) ++ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); ++ else ++ fwt_access.dir = FWT_DEFAULT_DIR; ++ ++#ifdef DEBUG ++ { ++ char ethaddr1_str[18], ethaddr2_str[18]; ++ lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str); ++ eth_addr2str(fwt_access.da, ethaddr1_str); ++ eth_addr2str(fwt_access.ra, ethaddr2_str); ++ lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, ++ ethaddr2_str, fwt_access.dir); ++ } ++#endif ++ ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_DEL, ++ CMD_OPTION_WAITFORRSP, 0, ++ (void *)&fwt_access); ++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); ++ return ret; ++} ++ ++ ++/** ++ * @brief Print route parameters ++ * @param fwt_access struct cmd_ds_fwt_access with route info ++ * @param buf destination buffer for route info ++ */ ++static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) ++{ ++ buf += sprintf(buf, " "); ++ buf += eth_addr2str(fwt_access.da, buf); ++ buf += sprintf(buf, " "); ++ buf += eth_addr2str(fwt_access.ra, buf); ++ buf += sprintf(buf, " %u", fwt_access.valid); ++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); ++ buf += sprintf(buf, " %u", fwt_access.dir); ++ buf += sprintf(buf, " %u", fwt_access.rate); ++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); ++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); ++ buf += sprintf(buf, " %u", fwt_access.hopcount); ++ buf += sprintf(buf, " %u", fwt_access.ttl); ++ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); ++ buf += sprintf(buf, " %u", fwt_access.sleepmode); ++ buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr)); ++ buf += eth_addr2str(fwt_access.prec, buf); ++} ++ ++/** ++ * @brief Lookup an entry in the FWT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_lookup_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char in_str[64]; ++ char *ptr; ++ static struct cmd_ds_fwt_access fwt_access; ++ static char out_str[128]; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) ++ return -EFAULT; ++ ++ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { ++ lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); ++ return -EINVAL; ++ } ++ ++#ifdef DEBUG ++ { ++ char ethaddr1_str[18]; ++ lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str); ++ eth_addr2str(fwt_access.da, ethaddr1_str); ++ lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); ++ } ++#endif ++ ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_LOOKUP, ++ CMD_OPTION_WAITFORRSP, 0, ++ (void *)&fwt_access); ++ ++ if (ret == 0) ++ print_route(fwt_access, out_str); ++ else ++ sprintf(out_str, "(null)"); ++ ++ wrq->u.data.length = strlen(out_str); ++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str, ++ wrq->u.data.length)) { ++ lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n"); ++ return -EFAULT; ++ } ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief Reset all entries from the FWT table ++ * @param priv A pointer to struct lbs_private structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_reset_ioctl(struct lbs_private * priv) ++{ ++ lbs_deb_ioctl("FWT: resetting\n"); ++ ++ return (lbs_prepare_and_send_command(priv, ++ CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_RESET, ++ CMD_OPTION_WAITFORRSP, 0, NULL)); ++} ++ ++/** ++ * @brief List an entry from the FWT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_list_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char in_str[8]; ++ static struct cmd_ds_fwt_access fwt_access; ++ char *ptr = in_str; ++ static char out_str[128]; ++ char *pbuf = out_str; ++ int ret = 0; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ ++#ifdef DEBUG ++ { ++ lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str); ++ lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); ++ } ++#endif ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_LIST, ++ CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access); ++ ++ if (ret == 0) ++ print_route(fwt_access, pbuf); ++ else ++ pbuf += sprintf(pbuf, " (null)"); ++ ++ wrq->u.data.length = strlen(out_str); ++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str, ++ wrq->u.data.length)) { ++ lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = 0; ++ ++out: ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return ret; ++} ++ ++/** ++ * @brief List an entry from the FRT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_list_route_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char in_str[64]; ++ static struct cmd_ds_fwt_access fwt_access; ++ char *ptr = in_str; ++ static char out_str[128]; ++ char *pbuf = out_str; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) ++ return -EFAULT; ++ ++ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ ++#ifdef DEBUG ++ { ++ lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str); ++ lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); ++ } ++#endif ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_LIST_ROUTE, ++ CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access); ++ ++ if (ret == 0) { ++ print_route(fwt_access, pbuf); ++ } else ++ pbuf += sprintf(pbuf, " (null)"); ++ ++ wrq->u.data.length = strlen(out_str); ++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str, ++ wrq->u.data.length)) { ++ lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n"); ++ return -EFAULT; ++ } ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief List an entry from the FNT table ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_list_neighbor_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ char in_str[8]; ++ static struct cmd_ds_fwt_access fwt_access; ++ char *ptr = in_str; ++ static char out_str[128]; ++ char *pbuf = out_str; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) ++ return -EFAULT; ++ ++ memset(&fwt_access, 0, sizeof(fwt_access)); ++ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ ++#ifdef DEBUG ++ { ++ lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str); ++ lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); ++ } ++#endif ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR, ++ CMD_OPTION_WAITFORRSP, 0, ++ (void *)&fwt_access); ++ ++ if (ret == 0) { ++ pbuf += sprintf(pbuf, " ra "); ++ pbuf += eth_addr2str(fwt_access.ra, pbuf); ++ pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); ++ pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); ++ pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); ++ } else ++ pbuf += sprintf(pbuf, " (null)"); ++ ++ wrq->u.data.length = strlen(out_str); ++ if (copy_to_user(wrq->u.data.pointer, (char *)out_str, ++ wrq->u.data.length)) { ++ lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n"); ++ return -EFAULT; ++ } ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief Cleans up the route (FRT) and neighbor (FNT) tables ++ * (Garbage Collection) ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_cleanup_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ static struct cmd_ds_fwt_access fwt_access; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ lbs_deb_ioctl("FWT: cleaning up\n"); ++ ++ memset(&fwt_access, 0, sizeof(fwt_access)); ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_CLEANUP, ++ CMD_OPTION_WAITFORRSP, 0, ++ (void *)&fwt_access); ++ ++ if (ret == 0) ++ wrq->u.param.value = le32_to_cpu(fwt_access.references); ++ else ++ return -EFAULT; ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++/** ++ * @brief Gets firmware internal time (debug purposes) ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_fwt_time_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ static struct cmd_ds_fwt_access fwt_access; ++ int ret; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ lbs_deb_ioctl("FWT: getting time\n"); ++ ++ memset(&fwt_access, 0, sizeof(fwt_access)); ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS, ++ CMD_ACT_FWT_ACCESS_TIME, ++ CMD_OPTION_WAITFORRSP, 0, ++ (void *)&fwt_access); ++ ++ if (ret == 0) ++ wrq->u.param.value = le32_to_cpu(fwt_access.references); ++ else ++ return -EFAULT; ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return 0; ++} ++ ++ ++/** ++ * @brief Manages all mesh related ioctls ++ * @param priv A pointer to struct lbs_private structure ++ * @param req A pointer to ifreq structure ++ * @param cmd The command type ++ * @param host_subcmd The device code for the subcommand ++ * 0: sets a value in the firmware ++ * 1: retrieves an int from the firmware ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_mesh_ioctl(struct lbs_private * priv, struct iwreq * wrq, ++ int cmd, int subcmd) ++{ ++ struct cmd_ds_mesh_access mesh_access; ++ int parameter; ++ char str[128]; ++ char *ptr = str; ++ int ret, i; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ memset(&mesh_access, 0, sizeof(mesh_access)); ++ ++ if (cmd == LBS_SETONEINT_GETNONE) { ++ parameter = SUBCMD_DATA(wrq); ++ ++ /* Convert rate from Mbps -> firmware rate index */ ++ if (subcmd == CMD_ACT_MESH_SET_BCAST_RATE) ++ parameter = lbs_data_rate_to_fw_index(parameter); ++ if (subcmd == CMD_ACT_MESH_SET_PRB_RSP_RETRY_LIMIT) { ++ if (parameter > 15) ++ return -EINVAL; ++ } ++ if (parameter < 0) ++ return -EINVAL; ++ mesh_access.data[0] = cpu_to_le32(parameter); ++ } else if (subcmd == CMD_ACT_MESH_SET_LINK_COSTS) { ++ if (copy_from_user(str, wrq->u.data.pointer, sizeof(str))) ++ return -EFAULT; ++ ++ for (i = 0; i < COSTS_LIST_SIZE; i++) { ++ mesh_access.data[i] = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); ++ if (!(ptr = next_param(ptr)) && i!= (COSTS_LIST_SIZE - 1)) ++ return -EINVAL; ++ } ++ } ++ ++ ret = lbs_mesh_access(priv, subcmd, &mesh_access); ++ ++ if (ret != 0) ++ return ret; ++ ++ if (cmd == LBS_SETNONE_GETONEINT) { ++ u32 data = le32_to_cpu(mesh_access.data[0]); ++ ++ if (subcmd == CMD_ACT_MESH_GET_BCAST_RATE) ++ wrq->u.param.value = lbs_fw_index_to_data_rate(data); ++ else ++ wrq->u.param.value = data; ++ } else if (subcmd == CMD_ACT_MESH_GET_LINK_COSTS) { ++ for (i = 0; i < COSTS_LIST_SIZE; i++) ++ ptr += sprintf (ptr, " %u", le32_to_cpu(mesh_access.data[i])); ++ wrq->u.data.length = strlen(str); ++ ++ if (copy_to_user(wrq->u.data.pointer, (char *)str, ++ wrq->u.data.length)) { ++ lbs_deb_ioctl("MESH_IOCTL: Copy to user failed!\n"); ++ ret = -EFAULT; ++ } ++ } ++ ++ lbs_deb_leave(LBS_DEB_IOCTL); ++ return ret; ++} ++ ++/** ++ * @brief Control Beacon transmissions ++ * @param priv A pointer to struct lbs_private structure ++ * @param wrq A pointer to iwreq structure ++ * @return 0 --success, otherwise fail ++ */ ++static int lbs_bcn_ioctl(struct lbs_private * priv, struct iwreq *wrq) ++{ ++ int ret; ++ int data[2]; ++ ++ memset(data, 0, sizeof(data)); ++ if (!wrq->u.data.length) { ++ lbs_deb_ioctl("Get Beacon control\n"); ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_BEACON_CTRL, ++ CMD_ACT_GET, ++ CMD_OPTION_WAITFORRSP, 0, NULL); ++ data[0] = priv->beacon_enable; ++ data[1] = priv->beacon_period; ++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { ++ lbs_deb_ioctl("Copy to user failed\n"); ++ return -EFAULT; ++ } ++#define GET_TWO_INT 2 ++ wrq->u.data.length = GET_TWO_INT; ++ } else { ++ lbs_deb_ioctl("Set beacon control\n"); ++ if (wrq->u.data.length > 2) ++ return -EINVAL; ++ if (copy_from_user (data, wrq->u.data.pointer, ++ sizeof(int) * wrq->u.data.length)) { ++ lbs_deb_ioctl("Copy from user failed\n"); ++ return -EFAULT; ++ } ++ priv->beacon_enable = data[0]; ++ if (wrq->u.data.length > 1) { ++ if ((data[1] > MRVDRV_MAX_BEACON_INTERVAL) ++ || (data[1] < MRVDRV_MIN_BEACON_INTERVAL)) ++ return -ENOTSUPP; ++ priv->beacon_period= data[1]; ++ } ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_BEACON_CTRL, ++ CMD_ACT_SET, ++ CMD_OPTION_WAITFORRSP, 0, NULL); ++ } ++ return ret; ++} ++ ++static int lbs_led_gpio_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ int i, ret = 0; ++ int data[16]; ++ struct cmd_ds_802_11_led_ctrl ctrl; ++ struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio *) ctrl.data; ++ int len = wrq->u.data.length; ++ ++ if ((len > MAX_LEDS * 2) || (len % 2 != 0)) ++ return -ENOTSUPP; ++ ++ memset(&ctrl, 0, sizeof(ctrl)); ++ if (len == 0) { ++ ctrl.action = cpu_to_le16(CMD_ACT_GET); ++ } else { ++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) { ++ lbs_deb_ioctl("Copy from user failed\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ctrl.action = cpu_to_le16(CMD_ACT_SET); ++ ctrl.numled = cpu_to_le16(0); ++ gpio->header.type = cpu_to_le16(TLV_TYPE_LED_GPIO); ++ gpio->header.len = cpu_to_le16(len); ++ for (i = 0; i < len; i += 2) { ++ gpio->ledpin[i / 2].led = data[i]; ++ gpio->ledpin[i / 2].pin = data[i + 1]; ++ } ++ } ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL, ++ 0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl); ++ if (ret) { ++ lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret); ++ goto out; ++ } ++ len = le16_to_cpu(gpio->header.len); ++ for (i = 0; i < len; i += 2) { ++ data[i] = gpio->ledpin[i / 2].led; ++ data[i + 1] = gpio->ledpin[i / 2].pin; ++ } ++ ++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * len)) { ++ lbs_deb_ioctl("Copy to user failed\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ wrq->u.data.length = len; ++ ++out: ++ return ret; ++} ++ ++ ++static int lbs_led_bhv_ioctl(struct lbs_private * priv, struct ifreq *req) ++{ ++ struct iwreq *wrq = (struct iwreq *)req; ++ int i, ret = 0; ++ int data[MAX_LEDS*4]; ++ int firmwarestate = 0; ++ struct cmd_ds_802_11_led_ctrl ctrl; ++ struct mrvlietypes_ledbhv *bhv = (struct mrvlietypes_ledbhv *) ctrl.data; ++ int len = wrq->u.data.length; ++ ++ if ((len > MAX_LEDS * 4) ||(len == 0) ) ++ return -ENOTSUPP; ++ ++ memset(&ctrl, 0, sizeof(ctrl)); ++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) { ++ lbs_deb_ioctl("Copy from user failed\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ if (len == 1) { ++ ctrl.action = cpu_to_le16(CMD_ACT_GET); ++ firmwarestate = data[0]; ++ } else { ++ ++ if (len % 4 != 0 ) ++ return -ENOTSUPP; ++ ++ bhv->header.type = cpu_to_le16(TLV_TYPE_LEDBEHAVIOR); ++ bhv->header.len = cpu_to_le16(len); ++ ctrl.action = cpu_to_le16(CMD_ACT_SET); ++ ctrl.numled = cpu_to_le16(0); ++ for (i = 0; i < len; i += 4) { ++ bhv->ledbhv[i / 4].firmwarestate = data[i]; ++ bhv->ledbhv[i / 4].led = data[i + 1]; ++ bhv->ledbhv[i / 4].ledstate = data[i + 2]; ++ bhv->ledbhv[i / 4].ledarg = data[i + 3]; ++ } ++ } ++ ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL, ++ 0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl); ++ if (ret) { ++ lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret); ++ goto out; ++ } ++ ++ /* Get LED behavior IE, we have received gpio control as well when len ++ is equal to 1. */ ++ if (len ==1 ) { ++ bhv = (struct mrvlietypes_ledbhv *) ++ ((unsigned char *)bhv->ledbhv + le16_to_cpu(bhv->header.len)); ++ i = 0; ++ while ( i < (MAX_LEDS*4) && ++ (bhv->header.type != cpu_to_le16(MRVL_TERMINATE_TLV_ID)) ) { ++ if (bhv->ledbhv[0].firmwarestate == firmwarestate) { ++ data[i++] = bhv->ledbhv[0].firmwarestate; ++ data[i++] = bhv->ledbhv[0].led; ++ data[i++] = bhv->ledbhv[0].ledstate; ++ data[i++] = bhv->ledbhv[0].ledarg; ++ } ++ bhv++; ++ } ++ len = i; ++ } else { ++ for (i = 0; i < le16_to_cpu(bhv->header.len); i += 4) { ++ data[i] = bhv->ledbhv[i / 4].firmwarestate; ++ data[i + 1] = bhv->ledbhv[i / 4].led; ++ data[i + 2] = bhv->ledbhv[i / 4].ledstate; ++ data[i + 3] = bhv->ledbhv[i / 4].ledarg; ++ } ++ len = le16_to_cpu(bhv->header.len); ++ } ++ ++ if (copy_to_user(wrq->u.data.pointer, data, ++ sizeof(int) * len)) { ++ lbs_deb_ioctl("Copy to user failed\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ wrq->u.data.length = len; ++ ++out: ++ return ret; ++} ++ ++/** ++ * @brief ioctl function - entry point ++ * ++ * @param dev A pointer to net_device structure ++ * @param req A pointer to ifreq structure ++ * @param cmd command ++ * @return 0--success, otherwise fail ++ */ ++int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) ++{ ++ int *pdata; ++ int ret = 0; ++ struct lbs_private *priv = dev->priv; ++ struct iwreq *wrq = (struct iwreq *)req; ++ ++ lbs_deb_enter(LBS_DEB_IOCTL); ++ ++ lbs_deb_ioctl("lbs_do_ioctl: ioctl cmd = 0x%x\n", cmd); ++ switch (cmd) { ++ case LBS_SETNONE_GETNONE: ++ switch (wrq->u.data.flags) { ++ case LBS_SUBCMD_BT_RESET: ++ lbs_bt_reset_ioctl(priv); ++ break; ++ case LBS_SUBCMD_FWT_RESET: ++ lbs_fwt_reset_ioctl(priv); ++ break; ++ } ++ break; ++ ++ case LBS_SETONEINT_GETNONE: ++ switch (wrq->u.mode) { ++ case LBS_SUBCMD_SET_REGION: ++ ret = lbs_set_region(priv, (u16) SUBCMD_DATA(wrq)); ++ break; ++ case LBS_SUBCMD_MESH_SET_TTL: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_SET_TTL); ++ break; ++ case LBS_SUBCMD_MESH_SET_BCAST_RATE: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_SET_BCAST_RATE); ++ break; ++ case LBS_SUBCMD_MESH_SET_RREQ_DELAY: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_SET_RREQ_DELAY); ++ break; ++ case LBS_SUBCMD_MESH_SET_ROUTE_EXP: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_SET_ROUTE_EXP); ++ break; ++ case LBS_SUBCMD_BT_SET_INVERT: ++ ret = lbs_bt_set_invert_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_MESH_SET_PRB_RSP_RETRY_LIMIT: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_SET_PRB_RSP_RETRY_LIMIT); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ break; ++ ++ case LBS_SET128CHAR_GET128CHAR: ++ switch ((int)wrq->u.data.flags) { ++ case LBS_SUBCMD_BT_ADD: ++ ret = lbs_bt_add_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_BT_DEL: ++ ret = lbs_bt_del_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_BT_LIST: ++ ret = lbs_bt_list_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_ADD: ++ ret = lbs_fwt_add_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_DEL: ++ ret = lbs_fwt_del_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_LOOKUP: ++ ret = lbs_fwt_lookup_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_LIST_NEIGHBOR: ++ ret = lbs_fwt_list_neighbor_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_LIST: ++ ret = lbs_fwt_list_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_LIST_ROUTE: ++ ret = lbs_fwt_list_route_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_MESH_SET_LINK_COSTS: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_SET_LINK_COSTS); ++ break ; ++ case LBS_SUBCMD_MESH_GET_LINK_COSTS: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_GET_LINK_COSTS); ++ break; ++ } ++ break; ++ ++ case LBS_SETNONE_GETONEINT: ++ switch (wrq->u.mode) { ++ case LBS_SUBCMD_GET_REGION: ++ pdata = (int *)wrq->u.name; ++ *pdata = (int)priv->regioncode; ++ break; ++ case LBS_SUBCMD_FWT_CLEANUP: ++ ret = lbs_fwt_cleanup_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_FWT_TIME: ++ ret = lbs_fwt_time_ioctl(priv, req); ++ break; ++ case LBS_SUBCMD_MESH_GET_TTL: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_GET_TTL); ++ break; ++ case LBS_SUBCMD_MESH_GET_BCAST_RATE: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_GET_BCAST_RATE); ++ break; ++ case LBS_SUBCMD_MESH_GET_RREQ_DELAY: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_GET_RREQ_DELAY); ++ break; ++ case LBS_SUBCMD_MESH_GET_ROUTE_EXP: ++ ret = lbs_mesh_ioctl(priv, wrq, cmd, ++ CMD_ACT_MESH_GET_ROUTE_EXP); ++ break; ++ case LBS_SUBCMD_BT_GET_INVERT: ++ ret = lbs_bt_get_invert_ioctl(priv, req); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ } ++ break; ++ ++ case LBS_SET_GET_SIXTEEN_INT: ++ switch ((int)wrq->u.data.flags) { ++ case LBS_LED_GPIO_CTRL: ++ ret = lbs_led_gpio_ioctl(priv, req); ++ break; ++ case LBS_BCN_CTRL: ++ ret = lbs_bcn_ioctl(priv,wrq); ++ break; ++ case LBS_LED_BEHAVIOR_CTRL: ++ ret = lbs_led_bhv_ioctl(priv, req); ++ break; ++ } ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); ++ return ret; ++} +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/ioctl.h linux-2.6.22-300/drivers/net/wireless/libertas/ioctl.h +--- linux-2.6.22-250/drivers/net/wireless/libertas/ioctl.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/ioctl.h 2008-06-05 18:10:06.000000000 -0400 +@@ -0,0 +1,50 @@ ++#define COSTS_LIST_SIZE 4 ++ ++/* iwpriv places the subcmd number in the first uint32_t; ++ data buffer follows that */ ++#define SUBCMD_OFFSET sizeof(uint32_t) ++#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) ++ ++/** Private ioctls and ioctls subcommands */ ++#define LBS_SETNONE_GETNONE (SIOCIWFIRSTPRIV + 8) ++#define LBS_SUBCMD_BT_RESET 13 ++#define LBS_SUBCMD_FWT_RESET 14 ++ ++#define LBS_SETNONE_GETONEINT (SIOCIWFIRSTPRIV + 15) ++#define LBS_SUBCMD_GET_REGION 1 ++#define LBS_SUBCMD_FWT_CLEANUP 15 ++#define LBS_SUBCMD_FWT_TIME 16 ++#define LBS_SUBCMD_MESH_GET_TTL 17 ++#define LBS_SUBCMD_BT_GET_INVERT 18 ++#define LBS_SUBCMD_MESH_GET_BCAST_RATE 19 ++#define LBS_SUBCMD_MESH_GET_RREQ_DELAY 20 ++#define LBS_SUBCMD_MESH_GET_ROUTE_EXP 21 ++ ++#define LBS_SETONEINT_GETNONE (SIOCIWFIRSTPRIV + 24) ++#define LBS_SUBCMD_SET_REGION 8 ++#define LBS_SUBCMD_MESH_SET_TTL 18 ++#define LBS_SUBCMD_BT_SET_INVERT 19 ++#define LBS_SUBCMD_MESH_SET_BCAST_RATE 20 ++#define LBS_SUBCMD_MESH_SET_RREQ_DELAY 21 ++#define LBS_SUBCMD_MESH_SET_ROUTE_EXP 22 ++#define LBS_SUBCMD_MESH_SET_PRB_RSP_RETRY_LIMIT 23 ++ ++#define LBS_SET128CHAR_GET128CHAR (SIOCIWFIRSTPRIV + 25) ++#define LBS_SUBCMD_BT_ADD 18 ++#define LBS_SUBCMD_BT_DEL 19 ++#define LBS_SUBCMD_BT_LIST 20 ++#define LBS_SUBCMD_FWT_ADD 21 ++#define LBS_SUBCMD_FWT_DEL 22 ++#define LBS_SUBCMD_FWT_LOOKUP 23 ++#define LBS_SUBCMD_FWT_LIST_NEIGHBOR 24 ++#define LBS_SUBCMD_FWT_LIST 25 ++#define LBS_SUBCMD_FWT_LIST_ROUTE 26 ++#define LBS_SUBCMD_MESH_SET_LINK_COSTS 27 ++#define LBS_SUBCMD_MESH_GET_LINK_COSTS 28 ++ ++#define LBS_SET_GET_SIXTEEN_INT (SIOCIWFIRSTPRIV + 29) ++#define LBS_LED_GPIO_CTRL 5 ++#define LBS_BCN_CTRL 6 ++#define LBS_LED_BEHAVIOR_CTRL 7 ++ ++int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int i); +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/join.c linux-2.6.22-300/drivers/net/wireless/libertas/join.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/join.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/join.c 2008-06-05 18:10:06.000000000 -0400 +@@ -17,154 +17,171 @@ + #include "dev.h" + #include "assoc.h" + +-#define AD_HOC_CAP_PRIVACY_ON 1 ++/* The firmware needs certain bits masked out of the beacon-derviced capability ++ * field when associating/joining to BSSs. ++ */ ++#define CAPINFO_MASK (~(0xda00)) + + /** +- * @brief This function finds out the common rates between rate1 and rate2. ++ * @brief This function finds common rates between rate1 and card rates. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * +- * @param adapter A pointer to wlan_adapter structure ++ * @param priv A pointer to struct lbs_private structure + * @param rate1 the buffer which keeps input and output +- * @param rate1_size the size of rate1 buffer +- * @param rate2 the buffer which keeps rate2 +- * @param rate2_size the size of rate2 buffer. ++ * @param rate1_size the size of rate1 buffer; new size of buffer on return + * + * @return 0 or -1 + */ +-static int get_common_rates(wlan_adapter * adapter, u8 * rate1, +- int rate1_size, u8 * rate2, int rate2_size) +-{ +- u8 *ptr = rate1; +- int ret = 0; ++static int get_common_rates(struct lbs_private *priv, ++ u8 *rates, ++ u16 *rates_size) ++{ ++ u8 *card_rates = lbs_bg_rates; ++ size_t num_card_rates = sizeof(lbs_bg_rates); ++ int ret = 0, i, j; + u8 tmp[30]; +- int i; ++ size_t tmp_size = 0; + +- memset(&tmp, 0, sizeof(tmp)); +- memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); +- memset(rate1, 0, rate1_size); +- +- /* Mask the top bit of the original values */ +- for (i = 0; tmp[i] && i < sizeof(tmp); i++) +- tmp[i] &= 0x7F; +- +- for (i = 0; rate2[i] && i < rate2_size; i++) { +- /* Check for Card Rate in tmp, excluding the top bit */ +- if (strchr(tmp, rate2[i] & 0x7F)) { +- /* values match, so copy the Card Rate to rate1 */ +- *rate1++ = rate2[i]; ++ /* For each rate in card_rates that exists in rate1, copy to tmp */ ++ for (i = 0; card_rates[i] && (i < num_card_rates); i++) { ++ for (j = 0; rates[j] && (j < *rates_size); j++) { ++ if (rates[j] == card_rates[i]) ++ tmp[tmp_size++] = card_rates[i]; + } + } + +- lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); +- lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); +- lbs_dbg_hex("Common rates:", ptr, rate1_size); +- lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate); +- +- if (!adapter->is_datarate_auto) { +- while (*ptr) { +- if ((*ptr & 0x7f) == adapter->datarate) { +- ret = 0; ++ lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); ++ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); ++ lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); ++ lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); ++ ++ if (!priv->auto_rate) { ++ for (i = 0; i < tmp_size; i++) { ++ if (tmp[i] == priv->cur_rate) + goto done; +- } +- ptr++; + } +- lbs_pr_alert( "Previously set fixed data rate %#x isn't " +- "compatible with the network.\n", adapter->datarate); +- ++ lbs_pr_alert("Previously set fixed data rate %#x isn't " ++ "compatible with the network.\n", priv->cur_rate); + ret = -1; + goto done; + } +- + ret = 0; ++ + done: ++ memset(rates, 0, *rates_size); ++ *rates_size = min_t(int, tmp_size, *rates_size); ++ memcpy(rates, tmp, *rates_size); + return ret; + } + +-int libertas_send_deauth(wlan_private * priv) ++ ++/** ++ * @brief Sets the MSB on basic rates as the firmware requires ++ * ++ * Scan through an array and set the MSB for basic data rates. ++ * ++ * @param rates buffer of data rates ++ * @param len size of buffer ++ */ ++static void lbs_set_basic_rate_flags(u8 *rates, size_t len) + { +- wlan_adapter *adapter = priv->adapter; +- int ret = 0; ++ int i; + +- if (adapter->mode == IW_MODE_INFRA && +- adapter->connect_status == libertas_connected) +- ret = libertas_send_deauthentication(priv); +- else +- ret = -ENOTSUPP; ++ for (i = 0; i < len; i++) { ++ if (rates[i] == 0x02 || rates[i] == 0x04 || ++ rates[i] == 0x0b || rates[i] == 0x16) ++ rates[i] |= 0x80; ++ } ++} + +- return ret; ++/** ++ * @brief Unsets the MSB on basic rates ++ * ++ * Scan through an array and unset the MSB for basic data rates. ++ * ++ * @param rates buffer of data rates ++ * @param len size of buffer ++ */ ++void lbs_unset_basic_rate_flags(u8 *rates, size_t len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ rates[i] &= 0x7f; + } + ++ + /** + * @brief Associate to a specific BSS discovered in a scan + * +- * @param priv A pointer to wlan_private structure ++ * @param priv A pointer to struct lbs_private structure + * @param pbssdesc Pointer to the BSS descriptor to associate with. + * + * @return 0-success, otherwise fail + */ +-int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) ++int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret; + +- lbs_deb_enter(LBS_DEB_JOIN); ++ lbs_deb_enter(LBS_DEB_ASSOC); + +- ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate, +- 0, cmd_option_waitforrsp, ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, ++ 0, CMD_OPTION_WAITFORRSP, + 0, assoc_req->bss.bssid); + + if (ret) + goto done; + + /* set preamble to firmware */ +- if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble) +- adapter->preamble = cmd_type_short_preamble; ++ if ( (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) ++ priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + else +- adapter->preamble = cmd_type_long_preamble; ++ priv->preamble = CMD_TYPE_LONG_PREAMBLE; + +- libertas_set_radio_control(priv); ++ lbs_set_radio_control(priv); + +- ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate, +- 0, cmd_option_waitforrsp, 0, assoc_req); ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, ++ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + + done: +- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); ++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + + /** + * @brief Start an Adhoc Network + * +- * @param priv A pointer to wlan_private structure ++ * @param priv A pointer to struct lbs_private structure + * @param adhocssid The ssid of the Adhoc Network + * @return 0--success, -1--fail + */ +-int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req) ++int lbs_start_adhoc_network(struct lbs_private *priv, ++ struct assoc_request *assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + +- adapter->adhoccreate = 1; ++ priv->adhoccreate = 1; + +- if (!adapter->capinfo.shortpreamble) { +- lbs_deb_join("AdhocStart: Long preamble\n"); +- adapter->preamble = cmd_type_long_preamble; +- } else { ++ if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { + lbs_deb_join("AdhocStart: Short preamble\n"); +- adapter->preamble = cmd_type_short_preamble; ++ priv->preamble = CMD_TYPE_SHORT_PREAMBLE; ++ } else { ++ lbs_deb_join("AdhocStart: Long preamble\n"); ++ priv->preamble = CMD_TYPE_LONG_PREAMBLE; + } + +- libertas_set_radio_control(priv); ++ lbs_set_radio_control(priv); + + lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); + lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); + +- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start, +- 0, cmd_option_waitforrsp, 0, assoc_req); ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, ++ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + + return ret; + } +@@ -172,107 +189,120 @@ int libertas_start_adhoc_network(wlan_pr + /** + * @brief Join an adhoc network found in a previous scan + * +- * @param priv A pointer to wlan_private structure ++ * @param priv A pointer to struct lbs_private structure + * @param pbssdesc Pointer to a BSS descriptor found in a previous scan + * to attempt to join + * + * @return 0--success, -1--fail + */ +-int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req) ++int lbs_join_adhoc_network(struct lbs_private *priv, ++ struct assoc_request *assoc_req) + { +- wlan_adapter *adapter = priv->adapter; + struct bss_descriptor * bss = &assoc_req->bss; + int ret = 0; + + lbs_deb_join("%s: Current SSID '%s', ssid length %u\n", + __func__, +- escape_essid(adapter->curbssparams.ssid, +- adapter->curbssparams.ssid_len), +- adapter->curbssparams.ssid_len); ++ escape_essid(priv->curbssparams.ssid, ++ priv->curbssparams.ssid_len), ++ priv->curbssparams.ssid_len); + lbs_deb_join("%s: requested ssid '%s', ssid length %u\n", + __func__, escape_essid(bss->ssid, bss->ssid_len), + bss->ssid_len); + + /* check if the requested SSID is already joined */ +- if (adapter->curbssparams.ssid_len +- && !libertas_ssid_cmp(adapter->curbssparams.ssid, +- adapter->curbssparams.ssid_len, ++ if ( priv->curbssparams.ssid_len ++ && !lbs_ssid_cmp(priv->curbssparams.ssid, ++ priv->curbssparams.ssid_len, + bss->ssid, bss->ssid_len) +- && (adapter->mode == IW_MODE_ADHOC)) { +- lbs_deb_join( +- "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " +- "not attempting to re-join"); +- return -1; ++ && (priv->mode == IW_MODE_ADHOC) ++ && (priv->connect_status == LBS_CONNECTED)) { ++ union iwreq_data wrqu; ++ ++ lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " ++ "current, not attempting to re-join"); ++ ++ /* Send the re-association event though, because the association ++ * request really was successful, even if just a null-op. ++ */ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ++ ETH_ALEN); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); ++ goto out; + } + +- /*Use shortpreamble only when both creator and card supports ++ /* Use shortpreamble only when both creator and card supports + short preamble */ +- if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) { ++ if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ || !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { + lbs_deb_join("AdhocJoin: Long preamble\n"); +- adapter->preamble = cmd_type_long_preamble; ++ priv->preamble = CMD_TYPE_LONG_PREAMBLE; + } else { + lbs_deb_join("AdhocJoin: Short preamble\n"); +- adapter->preamble = cmd_type_short_preamble; ++ priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + } + +- libertas_set_radio_control(priv); ++ lbs_set_radio_control(priv); + + lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); + lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); + +- adapter->adhoccreate = 0; ++ priv->adhoccreate = 0; + +- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join, +- 0, cmd_option_waitforrsp, ++ ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, ++ 0, CMD_OPTION_WAITFORRSP, + OID_802_11_SSID, assoc_req); + ++out: + return ret; + } + +-int libertas_stop_adhoc_network(wlan_private * priv) ++int lbs_stop_adhoc_network(struct lbs_private *priv) + { +- return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop, +- 0, cmd_option_waitforrsp, 0, NULL); ++ return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, ++ 0, CMD_OPTION_WAITFORRSP, 0, NULL); + } + + /** + * @brief Send Deauthentication Request + * +- * @param priv A pointer to wlan_private structure ++ * @param priv A pointer to struct lbs_private structure + * @return 0--success, -1--fail + */ +-int libertas_send_deauthentication(wlan_private * priv) ++int lbs_send_deauthentication(struct lbs_private *priv) + { +- return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate, +- 0, cmd_option_waitforrsp, 0, NULL); ++ return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, ++ 0, CMD_OPTION_WAITFORRSP, 0, NULL); + } + + /** + * @brief This function prepares command of authenticate. + * +- * @param priv A pointer to wlan_private structure ++ * @param priv A pointer to struct lbs_private structure + * @param cmd A pointer to cmd_ds_command structure + * @param pdata_buf Void cast of pointer to a BSSID to authenticate with + * + * @return 0 or -1 + */ +-int libertas_cmd_80211_authenticate(wlan_private * priv, ++int lbs_cmd_80211_authenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf) + { +- wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; + int ret = -1; + u8 *bssid = pdata_buf; ++ DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + +- cmd->command = cpu_to_le16(cmd_802_11_authenticate); ++ cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) + + S_DS_GEN); + + /* translate auth mode to 802.11 defined wire value */ +- switch (adapter->secinfo.auth_mode) { ++ switch (priv->secinfo.auth_mode) { + case IW_AUTH_ALG_OPEN_SYSTEM: + pauthenticate->authtype = 0x00; + break; +@@ -284,14 +314,14 @@ int libertas_cmd_80211_authenticate(wlan + break; + default: + lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", +- adapter->secinfo.auth_mode); ++ priv->secinfo.auth_mode); + goto out; + } + + memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); + +- lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n", +- MAC_ARG(bssid), pauthenticate->authtype); ++ lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", ++ print_mac(mac, bssid), pauthenticate->authtype); + ret = 0; + + out: +@@ -299,20 +329,19 @@ out: + return ret; + } + +-int libertas_cmd_80211_deauthenticate(wlan_private * priv, ++int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd) + { +- wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + + lbs_deb_enter(LBS_DEB_JOIN); + +- cmd->command = cpu_to_le16(cmd_802_11_deauthenticate); ++ cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* set AP MAC address */ +- memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN); ++ memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); + + /* Reason code 3 = Station is leaving */ + #define REASON_CODE_STA_LEAVING 3 +@@ -322,17 +351,14 @@ int libertas_cmd_80211_deauthenticate(wl + return 0; + } + +-int libertas_cmd_80211_associate(wlan_private * priv, ++int lbs_cmd_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) + { +- wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_associate *passo = &cmd->params.associate; + int ret = 0; + struct assoc_request * assoc_req = pdata_buf; + struct bss_descriptor * bss = &assoc_req->bss; +- u8 *card_rates; + u8 *pos; +- int card_rates_size; + u16 tmpcap, tmplen; + struct mrvlietypes_ssidparamset *ssid; + struct mrvlietypes_phyparamset *phy; +@@ -340,24 +366,24 @@ int libertas_cmd_80211_associate(wlan_pr + struct mrvlietypes_ratesparamset *rates; + struct mrvlietypes_rsnparamset *rsn; + +- lbs_deb_enter(LBS_DEB_JOIN); ++ lbs_deb_enter(LBS_DEB_ASSOC); + + pos = (u8 *) passo; + +- if (!adapter) { ++ if (!priv) { + ret = -1; + goto done; + } + +- cmd->command = cpu_to_le16(cmd_802_11_associate); ++ cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); + + memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); + pos += sizeof(passo->peerstaaddr); + + /* set the listen interval */ +- passo->listeninterval = cpu_to_le16(adapter->listeninterval); ++ passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); + +- pos += sizeof(passo->capinfo); ++ pos += sizeof(passo->capability); + pos += sizeof(passo->listeninterval); + pos += sizeof(passo->bcnperiod); + pos += sizeof(passo->dtimperiod); +@@ -386,23 +412,24 @@ int libertas_cmd_80211_associate(wlan_pr + + rates = (struct mrvlietypes_ratesparamset *) pos; + rates->header.type = cpu_to_le16(TLV_TYPE_RATES); +- +- memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES); +- +- card_rates = libertas_supported_rates; +- card_rates_size = sizeof(libertas_supported_rates); +- +- if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES, +- card_rates, card_rates_size)) { ++ memcpy(&rates->rates, &bss->rates, MAX_RATES); ++ tmplen = MAX_RATES; ++ if (get_common_rates(priv, rates->rates, &tmplen)) { + ret = -1; + goto done; + } +- +- tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES); +- adapter->curbssparams.numofrates = tmplen; +- + pos += sizeof(rates->header) + tmplen; + rates->header.len = cpu_to_le16(tmplen); ++ lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); ++ ++ /* Copy the infra. association rates into Current BSS state structure */ ++ memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); ++ memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); ++ ++ /* Set MSB on basic rates as the firmware requires, but _after_ ++ * copying to current bss rates. ++ */ ++ lbs_set_basic_rate_flags(rates->rates, tmplen); + + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { + rsn = (struct mrvlietypes_rsnparamset *) pos; +@@ -411,70 +438,56 @@ int libertas_cmd_80211_associate(wlan_pr + tmplen = (u16) assoc_req->wpa_ie[1]; + rsn->header.len = cpu_to_le16(tmplen); + memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); +- lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn, ++ lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, + sizeof(rsn->header) + tmplen); + pos += sizeof(rsn->header) + tmplen; + } + + /* update curbssparams */ +- adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; ++ priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; + +- /* Copy the infra. association rates into Current BSS state structure */ +- memcpy(&adapter->curbssparams.datarates, &rates->rates, +- min_t(size_t, sizeof(adapter->curbssparams.datarates), +- cpu_to_le16(rates->header.len))); +- +- lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n", +- cpu_to_le16(rates->header.len)); +- +- /* set IBSS field */ +- if (bss->mode == IW_MODE_INFRA) { +-#define CAPINFO_ESS_MODE 1 +- passo->capinfo.ess = CAPINFO_ESS_MODE; +- } +- +- if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ++ if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } + + cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); + +- /* set the capability info at last */ +- memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo)); +- tmpcap &= CAPINFO_MASK; +- lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", +- tmpcap, CAPINFO_MASK); +- memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo)); ++ /* set the capability info */ ++ tmpcap = (bss->capability & CAPINFO_MASK); ++ if (bss->mode == IW_MODE_INFRA) ++ tmpcap |= WLAN_CAPABILITY_ESS; ++ passo->capability = cpu_to_le16(tmpcap); ++ lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); + + done: +- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); ++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + +-int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, ++int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) + { +- wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; + int ret = 0; + int cmdappendsize = 0; +- int i; + struct assoc_request * assoc_req = pdata_buf; ++ u16 tmpcap = 0; ++ size_t ratesize = 0; + + lbs_deb_enter(LBS_DEB_JOIN); + +- if (!adapter) { ++ if (!priv) { + ret = -1; + goto done; + } + +- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start); ++ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); + + /* + * Fill in the parameters for 2 data structures: + * 1. cmd_ds_802_11_ad_hoc_start command +- * 2. adapter->scantable[i] ++ * 2. priv->scantable[i] + * + * Driver will fill up SSID, bsstype,IBSS param, Physical Param, + * probe delay, and cap info. +@@ -483,17 +496,19 @@ int libertas_cmd_80211_ad_hoc_start(wlan + * and operational rates. + */ + +- memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE); +- memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len); ++ memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); ++ memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); + + lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->ssid_len); + + /* set the BSS type */ +- adhs->bsstype = cmd_bss_type_ibss; +- adapter->mode = IW_MODE_ADHOC; +- adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod); ++ adhs->bsstype = CMD_BSS_TYPE_IBSS; ++ priv->mode = IW_MODE_ADHOC; ++ if (priv->beacon_period == 0) ++ priv->beacon_period = MRVDRV_BEACON_INTERVAL; ++ adhs->beaconperiod = cpu_to_le16(priv->beacon_period); + + /* set Physical param set */ + #define DS_PARA_IE_ID 3 +@@ -515,49 +530,40 @@ int libertas_cmd_80211_ad_hoc_start(wlan + + adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; + adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; +- adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow); ++ adhs->ssparamset.ibssparamset.atimwindow = 0; + + /* set capability info */ +- adhs->cap.ess = 0; +- adhs->cap.ibss = 1; +- +- /* probedelay */ +- adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); +- +- /* set up privacy in adapter->scantable[i] */ ++ tmpcap = WLAN_CAPABILITY_IBSS; + if (assoc_req->secinfo.wep_enabled) { + lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n"); +- adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON; ++ tmpcap |= WLAN_CAPABILITY_PRIVACY; + } else { + lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n"); + } ++ adhs->capability = cpu_to_le16(tmpcap); + +- memset(adhs->datarate, 0, sizeof(adhs->datarate)); +- +- if (adapter->adhoc_grate_enabled) { +- memcpy(adhs->datarate, libertas_adhoc_rates_g, +- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); +- } else { +- memcpy(adhs->datarate, libertas_adhoc_rates_b, +- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); +- } +- +- /* Find the last non zero */ +- for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ; ++ /* probedelay */ ++ adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + +- adapter->curbssparams.numofrates = i; ++ memset(adhs->rates, 0, sizeof(adhs->rates)); ++ ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); ++ memcpy(adhs->rates, lbs_bg_rates, ratesize); + + /* Copy the ad-hoc creating rates into Current BSS state structure */ +- memcpy(&adapter->curbssparams.datarates, +- &adhs->datarate, adapter->curbssparams.numofrates); ++ memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); ++ memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); ++ ++ /* Set MSB on basic rates as the firmware requires, but _after_ ++ * copying to current bss rates. ++ */ ++ lbs_set_basic_rate_flags(adhs->rates, ratesize); + + lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", +- adhs->datarate[0], adhs->datarate[1], +- adhs->datarate[2], adhs->datarate[3]); ++ adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); + + lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); + +- if (libertas_create_dnld_countryinfo_11d(priv)) { ++ if (lbs_create_dnld_countryinfo_11d(priv)) { + lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); + ret = -1; + goto done; +@@ -572,114 +578,96 @@ done: + return ret; + } + +-int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, ++int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv, + struct cmd_ds_command *cmd) + { +- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop); ++ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); + cmd->size = cpu_to_le16(S_DS_GEN); + + return 0; + } + +-int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, ++int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) + { +- wlan_adapter *adapter = priv->adapter; +- struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj; ++ struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; + struct assoc_request * assoc_req = pdata_buf; + struct bss_descriptor *bss = &assoc_req->bss; + int cmdappendsize = 0; + int ret = 0; +- u8 *card_rates; +- int card_rates_size; +- u16 tmpcap; +- int i; ++ u16 ratesize = 0; ++ DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + +- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); +- +- padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss; +- +- padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod); ++ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); + +- memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN); +- memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len); ++ join_cmd->bss.type = CMD_BSS_TYPE_IBSS; ++ join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); + +- memcpy(&padhocjoin->bssdescriptor.phyparamset, +- &bss->phyparamset, sizeof(union ieeetypes_phyparamset)); ++ memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); ++ memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); + +- memcpy(&padhocjoin->bssdescriptor.ssparamset, +- &bss->ssparamset, sizeof(union IEEEtypes_ssparamset)); ++ memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, ++ sizeof(union ieeetypes_phyparamset)); + +- memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo)); +- tmpcap &= CAPINFO_MASK; ++ memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, ++ sizeof(union IEEEtypes_ssparamset)); + ++ join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); + lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", +- tmpcap, CAPINFO_MASK); +- memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap, +- sizeof(struct ieeetypes_capinfo)); ++ bss->capability, CAPINFO_MASK); + + /* information on BSSID descriptor passed to FW */ + lbs_deb_join( +- "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n", +- MAC_ARG(padhocjoin->bssdescriptor.BSSID), +- padhocjoin->bssdescriptor.SSID); ++ "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", ++ print_mac(mac, join_cmd->bss.bssid), ++ join_cmd->bss.ssid); + + /* failtimeout */ +- padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); ++ join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + + /* probedelay */ +- padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); ++ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); ++ ++ priv->curbssparams.channel = bss->channel; + + /* Copy Data rates from the rates recorded in scan response */ +- memset(padhocjoin->bssdescriptor.datarates, 0, +- sizeof(padhocjoin->bssdescriptor.datarates)); +- memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates, +- min(sizeof(padhocjoin->bssdescriptor.datarates), +- sizeof(bss->datarates))); +- +- card_rates = libertas_supported_rates; +- card_rates_size = sizeof(libertas_supported_rates); +- +- adapter->curbssparams.channel = bss->channel; +- +- if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates, +- sizeof(padhocjoin->bssdescriptor.datarates), +- card_rates, card_rates_size)) { ++ memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); ++ ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); ++ memcpy(join_cmd->bss.rates, bss->rates, ratesize); ++ if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { + lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); + ret = -1; + goto done; + } + +- /* Find the last non zero */ +- for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates) +- && padhocjoin->bssdescriptor.datarates[i]; i++) ; +- +- adapter->curbssparams.numofrates = i; ++ /* Copy the ad-hoc creating rates into Current BSS state structure */ ++ memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); ++ memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); + +- /* +- * Copy the adhoc joining rates to Current BSS State structure ++ /* Set MSB on basic rates as the firmware requires, but _after_ ++ * copying to current bss rates. + */ +- memcpy(adapter->curbssparams.datarates, +- padhocjoin->bssdescriptor.datarates, +- adapter->curbssparams.numofrates); ++ lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); + +- padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow = ++ join_cmd->bss.ssparamset.ibssparamset.atimwindow = + cpu_to_le16(bss->atimwindow); + + if (assoc_req->secinfo.wep_enabled) { +- padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON; ++ u16 tmp = le16_to_cpu(join_cmd->bss.capability); ++ tmp |= WLAN_CAPABILITY_PRIVACY; ++ join_cmd->bss.capability = cpu_to_le16(tmp); + } + +- if (adapter->psmode == wlan802_11powermodemax_psp) { ++ if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + /* wake up first */ + __le32 Localpsmode; + +- Localpsmode = cpu_to_le32(wlan802_11powermodecam); +- ret = libertas_prepare_and_send_command(priv, +- cmd_802_11_ps_mode, +- cmd_act_set, ++ Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); ++ ret = lbs_prepare_and_send_command(priv, ++ CMD_802_11_PS_MODE, ++ CMD_ACT_SET, + 0, 0, &Localpsmode); + + if (ret) { +@@ -688,7 +676,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_ + } + } + +- if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ++ if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } +@@ -701,99 +689,131 @@ done: + return ret; + } + +-int libertas_ret_80211_associate(wlan_private * priv, ++int lbs_ret_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *resp) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + union iwreq_data wrqu; + struct ieeetypes_assocrsp *passocrsp; + struct bss_descriptor * bss; ++ u16 status_code; + +- lbs_deb_enter(LBS_DEB_JOIN); ++ lbs_deb_enter(LBS_DEB_ASSOC); + +- if (!adapter->in_progress_assoc_req) { +- lbs_deb_join("ASSOC_RESP: no in-progress association request\n"); ++ if (!priv->in_progress_assoc_req) { ++ lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); + ret = -1; + goto done; + } +- bss = &adapter->in_progress_assoc_req->bss; ++ bss = &priv->in_progress_assoc_req->bss; + + passocrsp = (struct ieeetypes_assocrsp *) & resp->params; + +- if (le16_to_cpu(passocrsp->statuscode)) { +- libertas_mac_event_disconnected(priv); ++ /* ++ * Older FW versions map the IEEE 802.11 Status Code in the association ++ * response to the following values returned in passocrsp->statuscode: ++ * ++ * IEEE Status Code Marvell Status Code ++ * 0 -> 0x0000 ASSOC_RESULT_SUCCESS ++ * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED ++ * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED ++ * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED ++ * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED ++ * others -> 0x0003 ASSOC_RESULT_REFUSED ++ * ++ * Other response codes: ++ * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) ++ * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for ++ * association response from the AP) ++ */ + +- lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n", +- le16_to_cpu(passocrsp->statuscode)); ++ status_code = le16_to_cpu(passocrsp->statuscode); ++ switch (status_code) { ++ case 0x00: ++ break; ++ case 0x01: ++ lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); ++ break; ++ case 0x02: ++ lbs_deb_assoc("ASSOC_RESP: internal timer " ++ "expired while waiting for the AP\n"); ++ break; ++ case 0x03: ++ lbs_deb_assoc("ASSOC_RESP: association " ++ "refused by AP\n"); ++ break; ++ case 0x04: ++ lbs_deb_assoc("ASSOC_RESP: authentication " ++ "refused by AP\n"); ++ break; ++ default: ++ lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " ++ " unknown\n", status_code); ++ break; ++ } + ++ if (status_code) { ++ lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + +- lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params, ++ lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, + le16_to_cpu(resp->size) - S_DS_GEN); + + /* Send a Media Connected event, according to the Spec */ +- adapter->connect_status = libertas_connected; +- +- lbs_deb_join("ASSOC_RESP: assocated to '%s'\n", +- escape_essid(bss->ssid, bss->ssid_len)); ++ priv->connect_status = LBS_CONNECTED; + + /* Update current SSID and BSSID */ +- memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); +- adapter->curbssparams.ssid_len = bss->ssid_len; +- memcpy(adapter->curbssparams.bssid, bss->bssid, ETH_ALEN); +- +- lbs_deb_join("ASSOC_RESP: currentpacketfilter is %x\n", +- adapter->currentpacketfilter); +- +- adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0; +- adapter->NF[TYPE_RXPD][TYPE_AVG] = 0; +- +- memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); +- memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); +- adapter->nextSNRNF = 0; +- adapter->numSNRNF = 0; ++ memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); ++ priv->curbssparams.ssid_len = bss->ssid_len; ++ memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); ++ ++ lbs_deb_assoc("ASSOC_RESP: mac_control is 0x%x\n", ++ priv->mac_control); ++ ++ priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; ++ priv->NF[TYPE_RXPD][TYPE_AVG] = 0; ++ ++ memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); ++ memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); ++ priv->nextSNRNF = 0; ++ priv->numSNRNF = 0; + + netif_carrier_on(priv->dev); +- netif_wake_queue(priv->dev); +- +- netif_carrier_on(priv->mesh_dev); +- netif_wake_queue(priv->mesh_dev); +- +- lbs_deb_join("ASSOC_RESP: Associated \n"); ++ if (!priv->tx_pending_len) ++ netif_wake_queue(priv->dev); + +- memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); ++ memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + done: +- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); ++ lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; + } + +-int libertas_ret_80211_disassociate(wlan_private * priv, ++int lbs_ret_80211_disassociate(struct lbs_private *priv, + struct cmd_ds_command *resp) + { + lbs_deb_enter(LBS_DEB_JOIN); + +- libertas_mac_event_disconnected(priv); ++ lbs_mac_event_disconnected(priv); + + lbs_deb_leave(LBS_DEB_JOIN); + return 0; + } + +-int libertas_ret_80211_ad_hoc_start(wlan_private * priv, ++int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *resp) + { +- wlan_adapter *adapter = priv->adapter; + int ret = 0; + u16 command = le16_to_cpu(resp->command); + u16 result = le16_to_cpu(resp->result); + struct cmd_ds_802_11_ad_hoc_result *padhocresult; + union iwreq_data wrqu; + struct bss_descriptor *bss; ++ DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + +@@ -803,20 +823,20 @@ int libertas_ret_80211_ad_hoc_start(wlan + lbs_deb_join("ADHOC_RESP: command = %x\n", command); + lbs_deb_join("ADHOC_RESP: result = %x\n", result); + +- if (!adapter->in_progress_assoc_req) { ++ if (!priv->in_progress_assoc_req) { + lbs_deb_join("ADHOC_RESP: no in-progress association request\n"); + ret = -1; + goto done; + } +- bss = &adapter->in_progress_assoc_req->bss; ++ bss = &priv->in_progress_assoc_req->bss; + + /* + * Join result code 0 --> SUCCESS + */ + if (result) { + lbs_deb_join("ADHOC_RESP: failed\n"); +- if (adapter->connect_status == libertas_connected) { +- libertas_mac_event_disconnected(priv); ++ if (priv->connect_status == LBS_CONNECTED) { ++ lbs_mac_event_disconnected(priv); + } + ret = -1; + goto done; +@@ -830,47 +850,45 @@ int libertas_ret_80211_ad_hoc_start(wlan + escape_essid(bss->ssid, bss->ssid_len)); + + /* Send a Media Connected event, according to the Spec */ +- adapter->connect_status = libertas_connected; ++ priv->connect_status = LBS_CONNECTED; + +- if (command == cmd_ret_802_11_ad_hoc_start) { ++ if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { + /* Update the created network descriptor with the new BSSID */ +- memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN); ++ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); + } + + /* Set the BSSID from the joined/started descriptor */ +- memcpy(&adapter->curbssparams.bssid, bss->bssid, ETH_ALEN); ++ memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + /* Set the new SSID to current SSID */ +- memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); +- adapter->curbssparams.ssid_len = bss->ssid_len; ++ memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); ++ priv->curbssparams.ssid_len = bss->ssid_len; + + netif_carrier_on(priv->dev); +- netif_wake_queue(priv->dev); +- +- netif_carrier_on(priv->mesh_dev); +- netif_wake_queue(priv->mesh_dev); ++ if (!priv->tx_pending_len) ++ netif_wake_queue(priv->dev); + + memset(&wrqu, 0, sizeof(wrqu)); +- memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); ++ memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); +- lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel); +- lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n", +- MAC_ARG(padhocresult->BSSID)); ++ lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); ++ lbs_deb_join("ADHOC_RESP: BSSID = %s\n", ++ print_mac(mac, padhocresult->bssid)); + + done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; + } + +-int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, ++int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv, + struct cmd_ds_command *resp) + { + lbs_deb_enter(LBS_DEB_JOIN); + +- libertas_mac_event_disconnected(priv); ++ lbs_mac_event_disconnected(priv); + + lbs_deb_leave(LBS_DEB_JOIN); + return 0; +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/join.h linux-2.6.22-300/drivers/net/wireless/libertas/join.h +--- linux-2.6.22-250/drivers/net/wireless/libertas/join.h 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/join.h 2008-06-05 18:10:06.000000000 -0400 +@@ -2,55 +2,52 @@ + * Interface for the wlan infrastructure and adhoc join routines + * + * Driver interface functions and type declarations for the join module +- * implemented in wlan_join.c. Process all start/join requests for ++ * implemented in join.c. Process all start/join requests for + * both adhoc and infrastructure networks + */ +-#ifndef _WLAN_JOIN_H +-#define _WLAN_JOIN_H ++#ifndef _LBS_JOIN_H ++#define _LBS_JOIN_H + + #include "defs.h" + #include "dev.h" + + struct cmd_ds_command; +-extern int libertas_cmd_80211_authenticate(wlan_private * priv, ++int lbs_cmd_80211_authenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +-extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, ++int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +-extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, ++int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv, + struct cmd_ds_command *cmd); +-extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, ++int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +-extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, ++int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, + struct cmd_ds_command *cmd); +-extern int libertas_cmd_80211_associate(wlan_private * priv, ++int lbs_cmd_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *cmd, + void *pdata_buf); + +-extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, ++int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, + struct cmd_ds_command *resp); +-extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, ++int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv, + struct cmd_ds_command *resp); +-extern int libertas_ret_80211_disassociate(wlan_private * priv, ++int lbs_ret_80211_disassociate(struct lbs_private *priv, + struct cmd_ds_command *resp); +-extern int libertas_ret_80211_associate(wlan_private * priv, ++int lbs_ret_80211_associate(struct lbs_private *priv, + struct cmd_ds_command *resp); + +-extern int libertas_reassociation_thread(void *data); +- +-extern int libertas_start_adhoc_network(wlan_private * priv, ++int lbs_start_adhoc_network(struct lbs_private *priv, + struct assoc_request * assoc_req); +-extern int libertas_join_adhoc_network(wlan_private * priv, ++int lbs_join_adhoc_network(struct lbs_private *priv, + struct assoc_request * assoc_req); +-extern int libertas_stop_adhoc_network(wlan_private * priv); ++int lbs_stop_adhoc_network(struct lbs_private *priv); + +-extern int libertas_send_deauthentication(wlan_private * priv); +-extern int libertas_send_deauth(wlan_private * priv); ++int lbs_send_deauthentication(struct lbs_private *priv); + +-extern int libertas_do_adhocstop_ioctl(wlan_private * priv); ++int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req); + +-int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); ++void lbs_unset_basic_rate_flags(u8 *rates, size_t len); + + #endif +diff -Nurp linux-2.6.22-250/drivers/net/wireless/libertas/main.c linux-2.6.22-300/drivers/net/wireless/libertas/main.c +--- linux-2.6.22-250/drivers/net/wireless/libertas/main.c 2007-07-08 19:32:17.000000000 -0400 ++++ linux-2.6.22-300/drivers/net/wireless/libertas/main.c 2008-06-05 18:10:06.000000000 -0400 +@@ -6,10 +6,12 @@ + + #include + #include +-#include + #include + #include + #include ++#include ++#include ++#include + + #include + #include +@@ -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 ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + #include + ++#include ++ + #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 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 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 + #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 +- +-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 ++#include + + #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 + #include +- +-/** 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 ++#include + + 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