aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/scan.c
diff options
context:
space:
mode:
authorShahar Levi <shahar_levi@ti.com>2010-11-08 06:20:10 -0500
committerLuciano Coelho <luciano.coelho@nokia.com>2010-11-22 09:45:09 -0500
commit00d201001bd4e8a46e3d03c970abcb72256c368b (patch)
tree2d3d6b971c9e0ac68ffd5edca1c596eeab247451 /drivers/net/wireless/wl12xx/scan.c
parenta76a574ca9ce7c05791cee42f000f2a42c687837 (diff)
wl1271: Change wl12xx Files Names
All files name prefix removed due to the fact that wl12xx driver supports wl1271 and wl1273. Also the definition in Kconfig and header files changed respectively. Signed-off-by: Shahar Levi <shahar_levi@ti.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/scan.c')
-rw-r--r--drivers/net/wireless/wl12xx/scan.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
new file mode 100644
index 000000000000..f3f2c5b011ee
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -0,0 +1,307 @@
1/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2009-2010 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/ieee80211.h>
25
26#include "wl12xx.h"
27#include "cmd.h"
28#include "scan.h"
29#include "acx.h"
30
31void wl1271_scan_complete_work(struct work_struct *work)
32{
33 struct delayed_work *dwork;
34 struct wl1271 *wl;
35
36 dwork = container_of(work, struct delayed_work, work);
37 wl = container_of(dwork, struct wl1271, scan_complete_work);
38
39 wl1271_debug(DEBUG_SCAN, "Scanning complete");
40
41 mutex_lock(&wl->mutex);
42
43 if (wl->scan.state == WL1271_SCAN_STATE_IDLE) {
44 mutex_unlock(&wl->mutex);
45 return;
46 }
47
48 wl->scan.state = WL1271_SCAN_STATE_IDLE;
49 kfree(wl->scan.scanned_ch);
50 wl->scan.scanned_ch = NULL;
51 wl->scan.req = NULL;
52 ieee80211_scan_completed(wl->hw, false);
53
54 if (wl->scan.failed) {
55 wl1271_info("Scan completed due to error.");
56 ieee80211_queue_work(wl->hw, &wl->recovery_work);
57 }
58 mutex_unlock(&wl->mutex);
59
60}
61
62
63static int wl1271_get_scan_channels(struct wl1271 *wl,
64 struct cfg80211_scan_request *req,
65 struct basic_scan_channel_params *channels,
66 enum ieee80211_band band, bool passive)
67{
68 struct conf_scan_settings *c = &wl->conf.scan;
69 int i, j;
70 u32 flags;
71
72 for (i = 0, j = 0;
73 i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
74 i++) {
75
76 flags = req->channels[i]->flags;
77
78 if (!wl->scan.scanned_ch[i] &&
79 !(flags & IEEE80211_CHAN_DISABLED) &&
80 ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
81 (req->channels[i]->band == band)) {
82
83 wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
84 req->channels[i]->band,
85 req->channels[i]->center_freq);
86 wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
87 req->channels[i]->hw_value,
88 req->channels[i]->flags);
89 wl1271_debug(DEBUG_SCAN,
90 "max_antenna_gain %d, max_power %d",
91 req->channels[i]->max_antenna_gain,
92 req->channels[i]->max_power);
93 wl1271_debug(DEBUG_SCAN, "beacon_found %d",
94 req->channels[i]->beacon_found);
95
96 if (!passive) {
97 channels[j].min_duration =
98 cpu_to_le32(c->min_dwell_time_active);
99 channels[j].max_duration =
100 cpu_to_le32(c->max_dwell_time_active);
101 } else {
102 channels[j].min_duration =
103 cpu_to_le32(c->min_dwell_time_passive);
104 channels[j].max_duration =
105 cpu_to_le32(c->max_dwell_time_passive);
106 }
107 channels[j].early_termination = 0;
108 channels[j].tx_power_att = req->channels[i]->max_power;
109 channels[j].channel = req->channels[i]->hw_value;
110
111 memset(&channels[j].bssid_lsb, 0xff, 4);
112 memset(&channels[j].bssid_msb, 0xff, 2);
113
114 /* Mark the channels we already used */
115 wl->scan.scanned_ch[i] = true;
116
117 j++;
118 }
119 }
120
121 return j;
122}
123
124#define WL1271_NOTHING_TO_SCAN 1
125
126static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
127 bool passive, u32 basic_rate)
128{
129 struct wl1271_cmd_scan *cmd;
130 struct wl1271_cmd_trigger_scan_to *trigger;
131 int ret;
132 u16 scan_options = 0;
133
134 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
135 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
136 if (!cmd || !trigger) {
137 ret = -ENOMEM;
138 goto out;
139 }
140
141 /* We always use high priority scans */
142 scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
143
144 /* No SSIDs means that we have a forced passive scan */
145 if (passive || wl->scan.req->n_ssids == 0)
146 scan_options |= WL1271_SCAN_OPT_PASSIVE;
147
148 cmd->params.scan_options = cpu_to_le16(scan_options);
149
150 cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
151 cmd->channels,
152 band, passive);
153 if (cmd->params.n_ch == 0) {
154 ret = WL1271_NOTHING_TO_SCAN;
155 goto out;
156 }
157
158 cmd->params.tx_rate = cpu_to_le32(basic_rate);
159 cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
160 cmd->params.rx_filter_options =
161 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
162
163 cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
164 cmd->params.tx_rate = cpu_to_le32(basic_rate);
165 cmd->params.tid_trigger = 0;
166 cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
167
168 if (band == IEEE80211_BAND_2GHZ)
169 cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
170 else
171 cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
172
173 if (wl->scan.ssid_len && wl->scan.ssid) {
174 cmd->params.ssid_len = wl->scan.ssid_len;
175 memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
176 }
177
178 ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
179 wl->scan.req->ie, wl->scan.req->ie_len,
180 band);
181 if (ret < 0) {
182 wl1271_error("PROBE request template failed");
183 goto out;
184 }
185
186 /* disable the timeout */
187 trigger->timeout = 0;
188 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
189 sizeof(*trigger), 0);
190 if (ret < 0) {
191 wl1271_error("trigger scan to failed for hw scan");
192 goto out;
193 }
194
195 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
196
197 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
198 if (ret < 0) {
199 wl1271_error("SCAN failed");
200 goto out;
201 }
202
203out:
204 kfree(cmd);
205 kfree(trigger);
206 return ret;
207}
208
209void wl1271_scan_stm(struct wl1271 *wl)
210{
211 int ret = 0;
212
213 switch (wl->scan.state) {
214 case WL1271_SCAN_STATE_IDLE:
215 break;
216
217 case WL1271_SCAN_STATE_2GHZ_ACTIVE:
218 ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
219 wl->conf.tx.basic_rate);
220 if (ret == WL1271_NOTHING_TO_SCAN) {
221 wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
222 wl1271_scan_stm(wl);
223 }
224
225 break;
226
227 case WL1271_SCAN_STATE_2GHZ_PASSIVE:
228 ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
229 wl->conf.tx.basic_rate);
230 if (ret == WL1271_NOTHING_TO_SCAN) {
231 if (wl->enable_11a)
232 wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
233 else
234 wl->scan.state = WL1271_SCAN_STATE_DONE;
235 wl1271_scan_stm(wl);
236 }
237
238 break;
239
240 case WL1271_SCAN_STATE_5GHZ_ACTIVE:
241 ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
242 wl->conf.tx.basic_rate_5);
243 if (ret == WL1271_NOTHING_TO_SCAN) {
244 wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
245 wl1271_scan_stm(wl);
246 }
247
248 break;
249
250 case WL1271_SCAN_STATE_5GHZ_PASSIVE:
251 ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
252 wl->conf.tx.basic_rate_5);
253 if (ret == WL1271_NOTHING_TO_SCAN) {
254 wl->scan.state = WL1271_SCAN_STATE_DONE;
255 wl1271_scan_stm(wl);
256 }
257
258 break;
259
260 case WL1271_SCAN_STATE_DONE:
261 wl->scan.failed = false;
262 cancel_delayed_work(&wl->scan_complete_work);
263 ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
264 msecs_to_jiffies(0));
265 break;
266
267 default:
268 wl1271_error("invalid scan state");
269 break;
270 }
271
272 if (ret < 0) {
273 cancel_delayed_work(&wl->scan_complete_work);
274 ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
275 msecs_to_jiffies(0));
276 }
277}
278
279int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
280 struct cfg80211_scan_request *req)
281{
282 if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
283 return -EBUSY;
284
285 wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
286
287 if (ssid_len && ssid) {
288 wl->scan.ssid_len = ssid_len;
289 memcpy(wl->scan.ssid, ssid, ssid_len);
290 } else {
291 wl->scan.ssid_len = 0;
292 }
293
294 wl->scan.req = req;
295
296 wl->scan.scanned_ch = kcalloc(req->n_channels,
297 sizeof(*wl->scan.scanned_ch),
298 GFP_KERNEL);
299 /* we assume failure so that timeout scenarios are handled correctly */
300 wl->scan.failed = true;
301 ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
302 msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
303
304 wl1271_scan_stm(wl);
305
306 return 0;
307}