aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_scan.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c
new file mode 100644
index 000000000000..eb9b4ece4ec3
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.c
@@ -0,0 +1,191 @@
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 "wl1271.h"
27#include "wl1271_cmd.h"
28#include "wl1271_scan.h"
29#include "wl1271_acx.h"
30
31int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
32 struct cfg80211_scan_request *req, u8 active_scan,
33 u8 high_prio, u8 band, u8 probe_requests)
34{
35
36 struct wl1271_cmd_trigger_scan_to *trigger = NULL;
37 struct wl1271_cmd_scan *params = NULL;
38 struct ieee80211_channel *channels;
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
73 if (!active_scan)
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
79 params->params.num_probe_requests = probe_requests;
80 params->params.tx_rate = cpu_to_le32(rate);
81 params->params.tid_trigger = 0;
82 params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
83
84 if (band == WL1271_SCAN_BAND_DUAL)
85 params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
86 else
87 params->params.band = band;
88
89 for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
90 if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
91 params->channels[j].min_duration =
92 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
93 params->channels[j].max_duration =
94 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
95 memset(&params->channels[j].bssid_lsb, 0xff, 4);
96 memset(&params->channels[j].bssid_msb, 0xff, 2);
97 params->channels[j].early_termination = 0;
98 params->channels[j].tx_power_att =
99 WL1271_SCAN_CURRENT_TX_PWR;
100 params->channels[j].channel = channels[i].hw_value;
101 j++;
102 }
103 }
104
105 params->params.num_channels = j;
106
107 if (ssid_len && ssid) {
108 params->params.ssid_len = ssid_len;
109 memcpy(params->params.ssid, ssid, ssid_len);
110 }
111
112 ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
113 req->ie, req->ie_len, ieee_band);
114 if (ret < 0) {
115 wl1271_error("PROBE request template failed");
116 goto out;
117 }
118
119 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
120 if (!trigger) {
121 ret = -ENOMEM;
122 goto out;
123 }
124
125 /* disable the timeout */
126 trigger->timeout = 0;
127
128 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
129 sizeof(*trigger), 0);
130 if (ret < 0) {
131 wl1271_error("trigger scan to failed for hw scan");
132 goto out;
133 }
134
135 wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
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
154 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
155 if (ret < 0) {
156 wl1271_error("SCAN failed");
157 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
158 goto out;
159 }
160
161out:
162 kfree(params);
163 kfree(trigger);
164 return ret;
165}
166
167int wl1271_scan_complete(struct wl1271 *wl)
168{
169 if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
170 if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
171 /* 2.4 GHz band scanned, scan 5 GHz band, pretend to
172 * the wl1271_scan function that we are not scanning
173 * as it checks that.
174 */
175 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
176 /* FIXME: ie missing! */
177 wl1271_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
178 wl->scan.req,
179 wl->scan.active,
180 wl->scan.high_prio,
181 WL1271_SCAN_BAND_5_GHZ,
182 wl->scan.probe_requests);
183 } else {
184 mutex_unlock(&wl->mutex);
185 ieee80211_scan_completed(wl->hw, false);
186 mutex_lock(&wl->mutex);
187 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
188 }
189 }
190 return 0;
191}