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