Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abb0b3bf authored by Teemu Paasikivi's avatar Teemu Paasikivi Committed by John W. Linville
Browse files

wl1271: Added support to scan on 5 GHz band



Added support to scan 802.11a access points on 5 GHz band when using
wl1273 chip.

Signed-off-by: default avatarTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Reviewed-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 311494c4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -299,6 +299,15 @@ struct wl1271_rx_mem_pool_addr {
	u32 addr_extra;
};

struct wl1271_scan {
	u8 state;
	u8 ssid[IW_ESSID_MAX_SIZE+1];
	size_t ssid_len;
	u8 active;
	u8 high_prio;
	u8 probe_requests;
};

struct wl1271 {
	struct ieee80211_hw *hw;
	bool mac80211_registered;
@@ -382,6 +391,7 @@ struct wl1271 {

	/* Are we currently scanning */
	bool scanning;
	struct wl1271_scan scan;

	/* Our association ID */
	u16 aid;
+96 −25
Original line number Diff line number Diff line
@@ -509,7 +509,7 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
}

int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
		    u8 active_scan, u8 high_prio, u8 num_channels,
		    u8 active_scan, u8 high_prio, u8 band,
		    u8 probe_requests)
{

@@ -518,12 +518,25 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
	struct ieee80211_channel *channels;
	int i, j, n_ch, ret;
	u16 scan_options = 0;
	u8 ieee_band;

	if (band == WL1271_SCAN_BAND_2_4_GHZ)
		ieee_band = IEEE80211_BAND_2GHZ;
	else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
		ieee_band = IEEE80211_BAND_2GHZ;
	else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
		ieee_band = IEEE80211_BAND_5GHZ;
	else
		return -EINVAL;

	if (wl->scanning)
	if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
		return -EINVAL;

	channels = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels;
	n_ch = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->n_channels;
	channels = wl->hw->wiphy->bands[ieee_band]->channels;
	n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;

	if (wl->scanning)
		return -EINVAL;

	params = kzalloc(sizeof(*params), GFP_KERNEL);
	if (!params)
@@ -540,10 +553,16 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
	params->params.scan_options = scan_options;

	params->params.num_probe_requests = probe_requests;
	params->params.tx_rate = cpu_to_le32(CONF_HW_BIT_RATE_2MBPS);
	/* Let the fw autodetect suitable tx_rate for probes */
	params->params.tx_rate = 0;
	params->params.tid_trigger = 0;
	params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;

	if (band == WL1271_SCAN_BAND_DUAL)
		params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
	else
		params->params.band = band;

	for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
		if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
			params->channels[j].min_duration =
@@ -567,7 +586,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
		memcpy(params->params.ssid, ssid, len);
	}

	ret = wl1271_cmd_build_probe_req(wl, ssid, len);
	ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band);
	if (ret < 0) {
		wl1271_error("PROBE request template failed");
		goto out;
@@ -592,6 +611,19 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
	wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));

	wl->scanning = true;
	if (wl1271_11a_enabled()) {
		wl->scan.state = band;
		if (band == WL1271_SCAN_BAND_DUAL) {
			wl->scan.active = active_scan;
			wl->scan.high_prio = high_prio;
			wl->scan.probe_requests = probe_requests;
			if (len && ssid) {
				wl->scan.ssid_len = len;
				memcpy(wl->scan.ssid, ssid, len);
			} else
				wl->scan.ssid_len = 0;
		}
	}

	ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
	if (ret < 0) {
@@ -654,22 +686,38 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
	return ret;
}

static int wl1271_build_basic_rates(char *rates)
static int wl1271_build_basic_rates(char *rates, u8 band)
{
	u8 index = 0;

	rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
	rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
	rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
	rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
	if (band == IEEE80211_BAND_2GHZ) {
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
	} else if (band == IEEE80211_BAND_5GHZ) {
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
	} else {
		wl1271_error("build_basic_rates invalid band: %d", band);
	}

	return index;
}

static int wl1271_build_extended_rates(char *rates)
static int wl1271_build_extended_rates(char *rates, u8 band)
{
	u8 index = 0;

	if (band == IEEE80211_BAND_2GHZ) {
		rates[index++] = IEEE80211_OFDM_RATE_6MB;
		rates[index++] = IEEE80211_OFDM_RATE_9MB;
		rates[index++] = IEEE80211_OFDM_RATE_12MB;
@@ -678,6 +726,22 @@ static int wl1271_build_extended_rates(char *rates)
		rates[index++] = IEEE80211_OFDM_RATE_36MB;
		rates[index++] = IEEE80211_OFDM_RATE_48MB;
		rates[index++] = IEEE80211_OFDM_RATE_54MB;
	} else if (band == IEEE80211_BAND_5GHZ) {
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
		rates[index++] =
			IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
	} else {
		wl1271_error("build_basic_rates invalid band: %d", band);
	}

	return index;
}
@@ -720,12 +784,14 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)

}

int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
			       u8 band)
{
	struct wl12xx_probe_req_template template;
	struct wl12xx_ie_rates *rates;
	char *ptr;
	u16 size;
	int ret;

	ptr = (char *)&template;
	size = sizeof(struct ieee80211_header);
@@ -747,20 +813,25 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
	/* Basic Rates */
	rates = (struct wl12xx_ie_rates *)ptr;
	rates->header.id = WLAN_EID_SUPP_RATES;
	rates->header.len = wl1271_build_basic_rates(rates->rates);
	rates->header.len = wl1271_build_basic_rates(rates->rates, band);
	size += sizeof(struct wl12xx_ie_header) + rates->header.len;
	ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;

	/* Extended rates */
	rates = (struct wl12xx_ie_rates *)ptr;
	rates->header.id = WLAN_EID_EXT_SUPP_RATES;
	rates->header.len = wl1271_build_extended_rates(rates->rates);
	rates->header.len = wl1271_build_extended_rates(rates->rates, band);
	size += sizeof(struct wl12xx_ie_header) + rates->header.len;

	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);

	return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
	if (band == IEEE80211_BAND_2GHZ)
		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
					      &template, size);
	else
		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
					      &template, size);
	return ret;
}

int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
+6 −2
Original line number Diff line number Diff line
@@ -39,13 +39,14 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
			   size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
		    u8 active_scan, u8 high_prio, u8 num_channels,
		    u8 active_scan, u8 high_prio, u8 band,
		    u8 probe_requests);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
			    void *buf, size_t buf_len);
int wl1271_cmd_build_null_data(struct wl1271 *wl);
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len);
int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
			       u8 band);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
		       u8 key_size, const u8 *key, const u8 *addr,
@@ -343,6 +344,9 @@ struct wl1271_cmd_set_keys {
#define WL1271_SCAN_OPT_PRIORITY_HIGH  4
#define WL1271_SCAN_CHAN_MIN_DURATION  30000  /* TU */
#define WL1271_SCAN_CHAN_MAX_DURATION  60000  /* TU */
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1
#define WL1271_SCAN_BAND_DUAL 2

struct basic_scan_params {
	u32 rx_config_options;
+29 −8
Original line number Diff line number Diff line
@@ -31,19 +31,40 @@
static int wl1271_event_scan_complete(struct wl1271 *wl,
				      struct event_mailbox *mbox)
{
	int size = sizeof(struct wl12xx_probe_req_template);
	wl1271_debug(DEBUG_EVENT, "status: 0x%x",
		     mbox->scheduled_scan_status);

	if (wl->scanning) {
		int size = sizeof(struct wl12xx_probe_req_template);
		wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
					size);
		if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
			wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
						NULL, size);
			/* 2.4 GHz band scanned, scan 5 GHz band, pretend
			 * to the wl1271_cmd_scan function that we are not
			 * scanning as it checks that.
			 */
			wl->scanning = false;
			wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
						wl->scan.active,
						wl->scan.high_prio,
						WL1271_SCAN_BAND_5_GHZ,
						wl->scan.probe_requests);
		} else {
			if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
				wl1271_cmd_template_set(wl,
						CMD_TEMPL_CFG_PROBE_REQ_2_4,
						NULL, size);
			else
				wl1271_cmd_template_set(wl,
						CMD_TEMPL_CFG_PROBE_REQ_5,
						NULL, size);

			mutex_unlock(&wl->mutex);
			ieee80211_scan_completed(wl->hw, false);
			mutex_lock(&wl->mutex);
			wl->scanning = false;
		}

	}
	return 0;
}

+8 −0
Original line number Diff line number Diff line
@@ -59,6 +59,14 @@ static int wl1271_init_templates_config(struct wl1271 *wl)
	if (ret < 0)
		return ret;

	if (wl1271_11a_enabled()) {
		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
				NULL,
				sizeof(struct wl12xx_probe_req_template));
		if (ret < 0)
			return ret;
	}

	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
				      sizeof(struct wl12xx_null_data_template));
	if (ret < 0)
Loading