aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_scan.c
diff options
context:
space:
mode:
authorLuciano Coelho <luciano.coelho@nokia.com>2010-07-08 10:50:07 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-08 16:42:09 -0400
commit08688d6b1a85484cc8e4a920afc60ffa6559999d (patch)
tree351ee3682ce623e15627df59aa50935ab6159ffe /drivers/net/wireless/wl12xx/wl1271_scan.c
parent34dd2aaac4a4b908c093980a9894fd878aeb6deb (diff)
wl1271: rewritten scanning code
This patch is a complete rewrite of the scanning code. It now includes a state machine to scan all four possible sets of channels independently: 2.4GHz active, 2.4GHz passive, 5GHz active and 5GHz passive. The wl1271 firmware doesn't allow these sets to be mixed, so up to several scan commands have to be issued. This patch also allows scanning more than 24 channels per set, by breaking the sets into smaller parts if needed (the firmware can scan a maximum of 24 channels at a time). Previously, the scanning code was erroneously scanning all channels possible actively, not complying with the CRDA values. This is also fixed with this patch. Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com> Reviewed-by: Saravanan Dhanabal <ext-saravanan.dhanabal@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_scan.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.c296
1 files changed, 181 insertions, 115 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c
index eb9b4ece4ec3..f938b33912f5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_scan.c
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.c
@@ -28,103 +28,120 @@
28#include "wl1271_scan.h" 28#include "wl1271_scan.h"
29#include "wl1271_acx.h" 29#include "wl1271_acx.h"
30 30
31int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, 31static int wl1271_get_scan_channels(struct wl1271 *wl,
32 struct cfg80211_scan_request *req, u8 active_scan, 32 struct cfg80211_scan_request *req,
33 u8 high_prio, u8 band, u8 probe_requests) 33 struct basic_scan_channel_params *channels,
34 enum ieee80211_band band, bool passive)
34{ 35{
36 int i, j;
37 u32 flags;
35 38
36 struct wl1271_cmd_trigger_scan_to *trigger = NULL; 39 for (i = 0, j = 0;
37 struct wl1271_cmd_scan *params = NULL; 40 i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
38 struct ieee80211_channel *channels; 41 i++) {
39 u32 rate;
40 int i, j, n_ch, ret;
41 u16 scan_options = 0;
42 u8 ieee_band;
43
44 if (band == WL1271_SCAN_BAND_2_4_GHZ) {
45 ieee_band = IEEE80211_BAND_2GHZ;
46 rate = wl->conf.tx.basic_rate;
47 } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
48 ieee_band = IEEE80211_BAND_2GHZ;
49 rate = wl->conf.tx.basic_rate;
50 } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
51 ieee_band = IEEE80211_BAND_5GHZ;
52 rate = wl->conf.tx.basic_rate_5;
53 } else
54 return -EINVAL;
55
56 if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
57 return -EINVAL;
58
59 channels = wl->hw->wiphy->bands[ieee_band]->channels;
60 n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
61
62 if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
63 return -EINVAL;
64
65 params = kzalloc(sizeof(*params), GFP_KERNEL);
66 if (!params)
67 return -ENOMEM;
68
69 params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
70 params->params.rx_filter_options =
71 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
72 42
73 if (!active_scan) 43 flags = req->channels[i]->flags;
74 scan_options |= WL1271_SCAN_OPT_PASSIVE;
75 if (high_prio)
76 scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
77 params->params.scan_options = cpu_to_le16(scan_options);
78 44
79 params->params.num_probe_requests = probe_requests; 45 if (!wl->scan.scanned_ch[i] &&
80 params->params.tx_rate = cpu_to_le32(rate); 46 !(flags & IEEE80211_CHAN_DISABLED) &&
81 params->params.tid_trigger = 0; 47 ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
82 params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; 48 (req->channels[i]->band == band)) {
83 49
84 if (band == WL1271_SCAN_BAND_DUAL) 50 wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
85 params->params.band = WL1271_SCAN_BAND_2_4_GHZ; 51 req->channels[i]->band,
86 else 52 req->channels[i]->center_freq);
87 params->params.band = band; 53 wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
54 req->channels[i]->hw_value,
55 req->channels[i]->flags);
56 wl1271_debug(DEBUG_SCAN,
57 "max_antenna_gain %d, max_power %d",
58 req->channels[i]->max_antenna_gain,
59 req->channels[i]->max_power);
60 wl1271_debug(DEBUG_SCAN, "beacon_found %d",
61 req->channels[i]->beacon_found);
88 62
89 for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { 63 channels[j].min_duration =
90 if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
91 params->channels[j].min_duration =
92 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); 64 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
93 params->channels[j].max_duration = 65 channels[j].max_duration =
94 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); 66 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
95 memset(&params->channels[j].bssid_lsb, 0xff, 4); 67 channels[j].early_termination = 0;
96 memset(&params->channels[j].bssid_msb, 0xff, 2); 68 channels[j].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR;
97 params->channels[j].early_termination = 0; 69 channels[j].channel = req->channels[i]->hw_value;
98 params->channels[j].tx_power_att = 70
99 WL1271_SCAN_CURRENT_TX_PWR; 71 memset(&channels[j].bssid_lsb, 0xff, 4);
100 params->channels[j].channel = channels[i].hw_value; 72 memset(&channels[j].bssid_msb, 0xff, 2);
73
74 /* Mark the channels we already used */
75 wl->scan.scanned_ch[i] = true;
76
101 j++; 77 j++;
102 } 78 }
103 } 79 }
104 80
105 params->params.num_channels = j; 81 return j;
82}
106 83
107 if (ssid_len && ssid) { 84#define WL1271_NOTHING_TO_SCAN 1
108 params->params.ssid_len = ssid_len; 85
109 memcpy(params->params.ssid, ssid, ssid_len); 86static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
87 bool passive, u32 basic_rate)
88{
89 struct wl1271_cmd_scan *cmd;
90 struct wl1271_cmd_trigger_scan_to *trigger;
91 int ret;
92 u16 scan_options = 0;
93
94 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
95 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
96 if (!cmd || !trigger) {
97 ret = -ENOMEM;
98 goto out;
110 } 99 }
111 100
112 ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, 101 /* We always use high priority scans */
113 req->ie, req->ie_len, ieee_band); 102 scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
114 if (ret < 0) { 103 if(passive)
115 wl1271_error("PROBE request template failed"); 104 scan_options |= WL1271_SCAN_OPT_PASSIVE;
105 cmd->params.scan_options = cpu_to_le16(scan_options);
106
107 cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
108 cmd->channels,
109 band, passive);
110 if (cmd->params.n_ch == 0) {
111 ret = WL1271_NOTHING_TO_SCAN;
116 goto out; 112 goto out;
117 } 113 }
118 114
119 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); 115 cmd->params.tx_rate = cpu_to_le32(basic_rate);
120 if (!trigger) { 116 cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
121 ret = -ENOMEM; 117 cmd->params.rx_filter_options =
118 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
119
120 cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS;
121 cmd->params.tx_rate = cpu_to_le32(basic_rate);
122 cmd->params.tid_trigger = 0;
123 cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
124
125 if (band == IEEE80211_BAND_2GHZ)
126 cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
127 else
128 cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
129
130 if (wl->scan.ssid_len && wl->scan.ssid) {
131 cmd->params.ssid_len = wl->scan.ssid_len;
132 memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
133 }
134
135 ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
136 wl->scan.req->ie, wl->scan.req->ie_len,
137 band);
138 if (ret < 0) {
139 wl1271_error("PROBE request template failed");
122 goto out; 140 goto out;
123 } 141 }
124 142
125 /* disable the timeout */ 143 /* disable the timeout */
126 trigger->timeout = 0; 144 trigger->timeout = 0;
127
128 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, 145 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
129 sizeof(*trigger), 0); 146 sizeof(*trigger), 0);
130 if (ret < 0) { 147 if (ret < 0) {
@@ -132,60 +149,109 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
132 goto out; 149 goto out;
133 } 150 }
134 151
135 wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); 152 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
136
137 set_bit(WL1271_FLAG_SCANNING, &wl->flags);
138 if (wl1271_11a_enabled()) {
139 wl->scan.state = band;
140 if (band == WL1271_SCAN_BAND_DUAL) {
141 wl->scan.active = active_scan;
142 wl->scan.high_prio = high_prio;
143 wl->scan.probe_requests = probe_requests;
144 if (ssid_len && ssid) {
145 wl->scan.ssid_len = ssid_len;
146 memcpy(wl->scan.ssid, ssid, ssid_len);
147 } else
148 wl->scan.ssid_len = 0;
149 wl->scan.req = req;
150 } else
151 wl->scan.req = NULL;
152 }
153 153
154 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); 154 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
155 if (ret < 0) { 155 if (ret < 0) {
156 wl1271_error("SCAN failed"); 156 wl1271_error("SCAN failed");
157 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
158 goto out; 157 goto out;
159 } 158 }
160 159
161out: 160out:
162 kfree(params); 161 kfree(cmd);
163 kfree(trigger); 162 kfree(trigger);
164 return ret; 163 return ret;
165} 164}
166 165
167int wl1271_scan_complete(struct wl1271 *wl) 166void wl1271_scan_stm(struct wl1271 *wl)
168{ 167{
169 if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { 168 int ret;
170 if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { 169
171 /* 2.4 GHz band scanned, scan 5 GHz band, pretend to 170 switch (wl->scan.state) {
172 * the wl1271_scan function that we are not scanning 171 case WL1271_SCAN_STATE_IDLE:
173 * as it checks that. 172 break;
174 */ 173
175 clear_bit(WL1271_FLAG_SCANNING, &wl->flags); 174 case WL1271_SCAN_STATE_2GHZ_ACTIVE:
176 /* FIXME: ie missing! */ 175 ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
177 wl1271_scan(wl, wl->scan.ssid, wl->scan.ssid_len, 176 wl->conf.tx.basic_rate);
178 wl->scan.req, 177 if (ret == WL1271_NOTHING_TO_SCAN) {
179 wl->scan.active, 178 wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
180 wl->scan.high_prio, 179 wl1271_scan_stm(wl);
181 WL1271_SCAN_BAND_5_GHZ, 180 }
182 wl->scan.probe_requests); 181
183 } else { 182 break;
184 mutex_unlock(&wl->mutex); 183
185 ieee80211_scan_completed(wl->hw, false); 184 case WL1271_SCAN_STATE_2GHZ_PASSIVE:
186 mutex_lock(&wl->mutex); 185 ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
187 clear_bit(WL1271_FLAG_SCANNING, &wl->flags); 186 wl->conf.tx.basic_rate);
187 if (ret == WL1271_NOTHING_TO_SCAN) {
188 if (wl1271_11a_enabled())
189 wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
190 else
191 wl->scan.state = WL1271_SCAN_STATE_DONE;
192 wl1271_scan_stm(wl);
188 } 193 }
194
195 break;
196
197 case WL1271_SCAN_STATE_5GHZ_ACTIVE:
198 ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
199 wl->conf.tx.basic_rate_5);
200 if (ret == WL1271_NOTHING_TO_SCAN) {
201 wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
202 wl1271_scan_stm(wl);
203 }
204
205 break;
206
207 case WL1271_SCAN_STATE_5GHZ_PASSIVE:
208 ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
209 wl->conf.tx.basic_rate_5);
210 if (ret == WL1271_NOTHING_TO_SCAN) {
211 wl->scan.state = WL1271_SCAN_STATE_DONE;
212 wl1271_scan_stm(wl);
213 }
214
215 break;
216
217 case WL1271_SCAN_STATE_DONE:
218 mutex_unlock(&wl->mutex);
219 ieee80211_scan_completed(wl->hw, false);
220 mutex_lock(&wl->mutex);
221
222 kfree(wl->scan.scanned_ch);
223 wl->scan.scanned_ch = NULL;
224
225 wl->scan.state = WL1271_SCAN_STATE_IDLE;
226 break;
227
228 default:
229 wl1271_error("invalid scan state");
230 break;
189 } 231 }
232}
233
234int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
235 struct cfg80211_scan_request *req)
236{
237 if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
238 return -EBUSY;
239
240 wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
241
242 if (ssid_len && ssid) {
243 wl->scan.ssid_len = ssid_len;
244 memcpy(wl->scan.ssid, ssid, ssid_len);
245 } else {
246 wl->scan.ssid_len = 0;
247 }
248
249 wl->scan.req = req;
250
251 wl->scan.scanned_ch = kzalloc(req->n_channels *
252 sizeof(*wl->scan.scanned_ch),
253 GFP_KERNEL);
254 wl1271_scan_stm(wl);
255
190 return 0; 256 return 0;
191} 257}