diff options
Diffstat (limited to 'drivers/net/wireless/iwlegacy/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlegacy/iwl-scan.c | 550 |
1 files changed, 0 insertions, 550 deletions
diff --git a/drivers/net/wireless/iwlegacy/iwl-scan.c b/drivers/net/wireless/iwlegacy/iwl-scan.c deleted file mode 100644 index 521b73b527d..00000000000 --- a/drivers/net/wireless/iwlegacy/iwl-scan.c +++ /dev/null | |||
@@ -1,550 +0,0 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * GPL LICENSE SUMMARY | ||
4 | * | ||
5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
19 | * USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution | ||
22 | * in the file called LICENSE.GPL. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | *****************************************************************************/ | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/export.h> | ||
32 | #include <net/mac80211.h> | ||
33 | |||
34 | #include "iwl-eeprom.h" | ||
35 | #include "iwl-dev.h" | ||
36 | #include "iwl-core.h" | ||
37 | #include "iwl-sta.h" | ||
38 | #include "iwl-io.h" | ||
39 | #include "iwl-helpers.h" | ||
40 | |||
41 | /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after | ||
42 | * sending probe req. This should be set long enough to hear probe responses | ||
43 | * from more than one AP. */ | ||
44 | #define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ | ||
45 | #define IWL_ACTIVE_DWELL_TIME_52 (20) | ||
46 | |||
47 | #define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) | ||
48 | #define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) | ||
49 | |||
50 | /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. | ||
51 | * Must be set longer than active dwell time. | ||
52 | * For the most reliable scan, set > AP beacon interval (typically 100msec). */ | ||
53 | #define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ | ||
54 | #define IWL_PASSIVE_DWELL_TIME_52 (10) | ||
55 | #define IWL_PASSIVE_DWELL_BASE (100) | ||
56 | #define IWL_CHANNEL_TUNE_TIME 5 | ||
57 | |||
58 | static int iwl_legacy_send_scan_abort(struct iwl_priv *priv) | ||
59 | { | ||
60 | int ret; | ||
61 | struct iwl_rx_packet *pkt; | ||
62 | struct iwl_host_cmd cmd = { | ||
63 | .id = REPLY_SCAN_ABORT_CMD, | ||
64 | .flags = CMD_WANT_SKB, | ||
65 | }; | ||
66 | |||
67 | /* Exit instantly with error when device is not ready | ||
68 | * to receive scan abort command or it does not perform | ||
69 | * hardware scan currently */ | ||
70 | if (!test_bit(STATUS_READY, &priv->status) || | ||
71 | !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || | ||
72 | !test_bit(STATUS_SCAN_HW, &priv->status) || | ||
73 | test_bit(STATUS_FW_ERROR, &priv->status) || | ||
74 | test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
75 | return -EIO; | ||
76 | |||
77 | ret = iwl_legacy_send_cmd_sync(priv, &cmd); | ||
78 | if (ret) | ||
79 | return ret; | ||
80 | |||
81 | pkt = (struct iwl_rx_packet *)cmd.reply_page; | ||
82 | if (pkt->u.status != CAN_ABORT_STATUS) { | ||
83 | /* The scan abort will return 1 for success or | ||
84 | * 2 for "failure". A failure condition can be | ||
85 | * due to simply not being in an active scan which | ||
86 | * can occur if we send the scan abort before we | ||
87 | * the microcode has notified us that a scan is | ||
88 | * completed. */ | ||
89 | IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status); | ||
90 | ret = -EIO; | ||
91 | } | ||
92 | |||
93 | iwl_legacy_free_pages(priv, cmd.reply_page); | ||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | static void iwl_legacy_complete_scan(struct iwl_priv *priv, bool aborted) | ||
98 | { | ||
99 | /* check if scan was requested from mac80211 */ | ||
100 | if (priv->scan_request) { | ||
101 | IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); | ||
102 | ieee80211_scan_completed(priv->hw, aborted); | ||
103 | } | ||
104 | |||
105 | priv->scan_vif = NULL; | ||
106 | priv->scan_request = NULL; | ||
107 | } | ||
108 | |||
109 | void iwl_legacy_force_scan_end(struct iwl_priv *priv) | ||
110 | { | ||
111 | lockdep_assert_held(&priv->mutex); | ||
112 | |||
113 | if (!test_bit(STATUS_SCANNING, &priv->status)) { | ||
114 | IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n"); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | IWL_DEBUG_SCAN(priv, "Forcing scan end\n"); | ||
119 | clear_bit(STATUS_SCANNING, &priv->status); | ||
120 | clear_bit(STATUS_SCAN_HW, &priv->status); | ||
121 | clear_bit(STATUS_SCAN_ABORTING, &priv->status); | ||
122 | iwl_legacy_complete_scan(priv, true); | ||
123 | } | ||
124 | |||
125 | static void iwl_legacy_do_scan_abort(struct iwl_priv *priv) | ||
126 | { | ||
127 | int ret; | ||
128 | |||
129 | lockdep_assert_held(&priv->mutex); | ||
130 | |||
131 | if (!test_bit(STATUS_SCANNING, &priv->status)) { | ||
132 | IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n"); | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) { | ||
137 | IWL_DEBUG_SCAN(priv, "Scan abort in progress\n"); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | ret = iwl_legacy_send_scan_abort(priv); | ||
142 | if (ret) { | ||
143 | IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret); | ||
144 | iwl_legacy_force_scan_end(priv); | ||
145 | } else | ||
146 | IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n"); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * iwl_scan_cancel - Cancel any currently executing HW scan | ||
151 | */ | ||
152 | int iwl_legacy_scan_cancel(struct iwl_priv *priv) | ||
153 | { | ||
154 | IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); | ||
155 | queue_work(priv->workqueue, &priv->abort_scan); | ||
156 | return 0; | ||
157 | } | ||
158 | EXPORT_SYMBOL(iwl_legacy_scan_cancel); | ||
159 | |||
160 | /** | ||
161 | * iwl_legacy_scan_cancel_timeout - Cancel any currently executing HW scan | ||
162 | * @ms: amount of time to wait (in milliseconds) for scan to abort | ||
163 | * | ||
164 | */ | ||
165 | int iwl_legacy_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) | ||
166 | { | ||
167 | unsigned long timeout = jiffies + msecs_to_jiffies(ms); | ||
168 | |||
169 | lockdep_assert_held(&priv->mutex); | ||
170 | |||
171 | IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n"); | ||
172 | |||
173 | iwl_legacy_do_scan_abort(priv); | ||
174 | |||
175 | while (time_before_eq(jiffies, timeout)) { | ||
176 | if (!test_bit(STATUS_SCAN_HW, &priv->status)) | ||
177 | break; | ||
178 | msleep(20); | ||
179 | } | ||
180 | |||
181 | return test_bit(STATUS_SCAN_HW, &priv->status); | ||
182 | } | ||
183 | EXPORT_SYMBOL(iwl_legacy_scan_cancel_timeout); | ||
184 | |||
185 | /* Service response to REPLY_SCAN_CMD (0x80) */ | ||
186 | static void iwl_legacy_rx_reply_scan(struct iwl_priv *priv, | ||
187 | struct iwl_rx_mem_buffer *rxb) | ||
188 | { | ||
189 | #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG | ||
190 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
191 | struct iwl_scanreq_notification *notif = | ||
192 | (struct iwl_scanreq_notification *)pkt->u.raw; | ||
193 | |||
194 | IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | /* Service SCAN_START_NOTIFICATION (0x82) */ | ||
199 | static void iwl_legacy_rx_scan_start_notif(struct iwl_priv *priv, | ||
200 | struct iwl_rx_mem_buffer *rxb) | ||
201 | { | ||
202 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
203 | struct iwl_scanstart_notification *notif = | ||
204 | (struct iwl_scanstart_notification *)pkt->u.raw; | ||
205 | priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); | ||
206 | IWL_DEBUG_SCAN(priv, "Scan start: " | ||
207 | "%d [802.11%s] " | ||
208 | "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", | ||
209 | notif->channel, | ||
210 | notif->band ? "bg" : "a", | ||
211 | le32_to_cpu(notif->tsf_high), | ||
212 | le32_to_cpu(notif->tsf_low), | ||
213 | notif->status, notif->beacon_timer); | ||
214 | } | ||
215 | |||
216 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ | ||
217 | static void iwl_legacy_rx_scan_results_notif(struct iwl_priv *priv, | ||
218 | struct iwl_rx_mem_buffer *rxb) | ||
219 | { | ||
220 | #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG | ||
221 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
222 | struct iwl_scanresults_notification *notif = | ||
223 | (struct iwl_scanresults_notification *)pkt->u.raw; | ||
224 | |||
225 | IWL_DEBUG_SCAN(priv, "Scan ch.res: " | ||
226 | "%d [802.11%s] " | ||
227 | "(TSF: 0x%08X:%08X) - %d " | ||
228 | "elapsed=%lu usec\n", | ||
229 | notif->channel, | ||
230 | notif->band ? "bg" : "a", | ||
231 | le32_to_cpu(notif->tsf_high), | ||
232 | le32_to_cpu(notif->tsf_low), | ||
233 | le32_to_cpu(notif->statistics[0]), | ||
234 | le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); | ||
235 | #endif | ||
236 | } | ||
237 | |||
238 | /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ | ||
239 | static void iwl_legacy_rx_scan_complete_notif(struct iwl_priv *priv, | ||
240 | struct iwl_rx_mem_buffer *rxb) | ||
241 | { | ||
242 | |||
243 | #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG | ||
244 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
245 | struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; | ||
246 | #endif | ||
247 | |||
248 | IWL_DEBUG_SCAN(priv, | ||
249 | "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", | ||
250 | scan_notif->scanned_channels, | ||
251 | scan_notif->tsf_low, | ||
252 | scan_notif->tsf_high, scan_notif->status); | ||
253 | |||
254 | /* The HW is no longer scanning */ | ||
255 | clear_bit(STATUS_SCAN_HW, &priv->status); | ||
256 | |||
257 | IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n", | ||
258 | (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", | ||
259 | jiffies_to_msecs(jiffies - priv->scan_start)); | ||
260 | |||
261 | queue_work(priv->workqueue, &priv->scan_completed); | ||
262 | } | ||
263 | |||
264 | void iwl_legacy_setup_rx_scan_handlers(struct iwl_priv *priv) | ||
265 | { | ||
266 | /* scan handlers */ | ||
267 | priv->rx_handlers[REPLY_SCAN_CMD] = iwl_legacy_rx_reply_scan; | ||
268 | priv->rx_handlers[SCAN_START_NOTIFICATION] = | ||
269 | iwl_legacy_rx_scan_start_notif; | ||
270 | priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = | ||
271 | iwl_legacy_rx_scan_results_notif; | ||
272 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = | ||
273 | iwl_legacy_rx_scan_complete_notif; | ||
274 | } | ||
275 | EXPORT_SYMBOL(iwl_legacy_setup_rx_scan_handlers); | ||
276 | |||
277 | inline u16 iwl_legacy_get_active_dwell_time(struct iwl_priv *priv, | ||
278 | enum ieee80211_band band, | ||
279 | u8 n_probes) | ||
280 | { | ||
281 | if (band == IEEE80211_BAND_5GHZ) | ||
282 | return IWL_ACTIVE_DWELL_TIME_52 + | ||
283 | IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); | ||
284 | else | ||
285 | return IWL_ACTIVE_DWELL_TIME_24 + | ||
286 | IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); | ||
287 | } | ||
288 | EXPORT_SYMBOL(iwl_legacy_get_active_dwell_time); | ||
289 | |||
290 | u16 iwl_legacy_get_passive_dwell_time(struct iwl_priv *priv, | ||
291 | enum ieee80211_band band, | ||
292 | struct ieee80211_vif *vif) | ||
293 | { | ||
294 | struct iwl_rxon_context *ctx; | ||
295 | u16 passive = (band == IEEE80211_BAND_2GHZ) ? | ||
296 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : | ||
297 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; | ||
298 | |||
299 | if (iwl_legacy_is_any_associated(priv)) { | ||
300 | /* | ||
301 | * If we're associated, we clamp the maximum passive | ||
302 | * dwell time to be 98% of the smallest beacon interval | ||
303 | * (minus 2 * channel tune time) | ||
304 | */ | ||
305 | for_each_context(priv, ctx) { | ||
306 | u16 value; | ||
307 | |||
308 | if (!iwl_legacy_is_associated_ctx(ctx)) | ||
309 | continue; | ||
310 | value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0; | ||
311 | if ((value > IWL_PASSIVE_DWELL_BASE) || !value) | ||
312 | value = IWL_PASSIVE_DWELL_BASE; | ||
313 | value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; | ||
314 | passive = min(value, passive); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | return passive; | ||
319 | } | ||
320 | EXPORT_SYMBOL(iwl_legacy_get_passive_dwell_time); | ||
321 | |||
322 | void iwl_legacy_init_scan_params(struct iwl_priv *priv) | ||
323 | { | ||
324 | u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; | ||
325 | if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) | ||
326 | priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; | ||
327 | if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) | ||
328 | priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; | ||
329 | } | ||
330 | EXPORT_SYMBOL(iwl_legacy_init_scan_params); | ||
331 | |||
332 | static int iwl_legacy_scan_initiate(struct iwl_priv *priv, | ||
333 | struct ieee80211_vif *vif) | ||
334 | { | ||
335 | int ret; | ||
336 | |||
337 | lockdep_assert_held(&priv->mutex); | ||
338 | |||
339 | if (WARN_ON(!priv->cfg->ops->utils->request_scan)) | ||
340 | return -EOPNOTSUPP; | ||
341 | |||
342 | cancel_delayed_work(&priv->scan_check); | ||
343 | |||
344 | if (!iwl_legacy_is_ready_rf(priv)) { | ||
345 | IWL_WARN(priv, "Request scan called when driver not ready.\n"); | ||
346 | return -EIO; | ||
347 | } | ||
348 | |||
349 | if (test_bit(STATUS_SCAN_HW, &priv->status)) { | ||
350 | IWL_DEBUG_SCAN(priv, | ||
351 | "Multiple concurrent scan requests in parallel.\n"); | ||
352 | return -EBUSY; | ||
353 | } | ||
354 | |||
355 | if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { | ||
356 | IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n"); | ||
357 | return -EBUSY; | ||
358 | } | ||
359 | |||
360 | IWL_DEBUG_SCAN(priv, "Starting scan...\n"); | ||
361 | |||
362 | set_bit(STATUS_SCANNING, &priv->status); | ||
363 | priv->scan_start = jiffies; | ||
364 | |||
365 | ret = priv->cfg->ops->utils->request_scan(priv, vif); | ||
366 | if (ret) { | ||
367 | clear_bit(STATUS_SCANNING, &priv->status); | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | queue_delayed_work(priv->workqueue, &priv->scan_check, | ||
372 | IWL_SCAN_CHECK_WATCHDOG); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | int iwl_legacy_mac_hw_scan(struct ieee80211_hw *hw, | ||
378 | struct ieee80211_vif *vif, | ||
379 | struct cfg80211_scan_request *req) | ||
380 | { | ||
381 | struct iwl_priv *priv = hw->priv; | ||
382 | int ret; | ||
383 | |||
384 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
385 | |||
386 | if (req->n_channels == 0) | ||
387 | return -EINVAL; | ||
388 | |||
389 | mutex_lock(&priv->mutex); | ||
390 | |||
391 | if (test_bit(STATUS_SCANNING, &priv->status)) { | ||
392 | IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); | ||
393 | ret = -EAGAIN; | ||
394 | goto out_unlock; | ||
395 | } | ||
396 | |||
397 | /* mac80211 will only ask for one band at a time */ | ||
398 | priv->scan_request = req; | ||
399 | priv->scan_vif = vif; | ||
400 | priv->scan_band = req->channels[0]->band; | ||
401 | |||
402 | ret = iwl_legacy_scan_initiate(priv, vif); | ||
403 | |||
404 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
405 | |||
406 | out_unlock: | ||
407 | mutex_unlock(&priv->mutex); | ||
408 | |||
409 | return ret; | ||
410 | } | ||
411 | EXPORT_SYMBOL(iwl_legacy_mac_hw_scan); | ||
412 | |||
413 | static void iwl_legacy_bg_scan_check(struct work_struct *data) | ||
414 | { | ||
415 | struct iwl_priv *priv = | ||
416 | container_of(data, struct iwl_priv, scan_check.work); | ||
417 | |||
418 | IWL_DEBUG_SCAN(priv, "Scan check work\n"); | ||
419 | |||
420 | /* Since we are here firmware does not finish scan and | ||
421 | * most likely is in bad shape, so we don't bother to | ||
422 | * send abort command, just force scan complete to mac80211 */ | ||
423 | mutex_lock(&priv->mutex); | ||
424 | iwl_legacy_force_scan_end(priv); | ||
425 | mutex_unlock(&priv->mutex); | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * iwl_legacy_fill_probe_req - fill in all required fields and IE for probe request | ||
430 | */ | ||
431 | |||
432 | u16 | ||
433 | iwl_legacy_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, | ||
434 | const u8 *ta, const u8 *ies, int ie_len, int left) | ||
435 | { | ||
436 | int len = 0; | ||
437 | u8 *pos = NULL; | ||
438 | |||
439 | /* Make sure there is enough space for the probe request, | ||
440 | * two mandatory IEs and the data */ | ||
441 | left -= 24; | ||
442 | if (left < 0) | ||
443 | return 0; | ||
444 | |||
445 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
446 | memcpy(frame->da, iwlegacy_bcast_addr, ETH_ALEN); | ||
447 | memcpy(frame->sa, ta, ETH_ALEN); | ||
448 | memcpy(frame->bssid, iwlegacy_bcast_addr, ETH_ALEN); | ||
449 | frame->seq_ctrl = 0; | ||
450 | |||
451 | len += 24; | ||
452 | |||
453 | /* ...next IE... */ | ||
454 | pos = &frame->u.probe_req.variable[0]; | ||
455 | |||
456 | /* fill in our indirect SSID IE */ | ||
457 | left -= 2; | ||
458 | if (left < 0) | ||
459 | return 0; | ||
460 | *pos++ = WLAN_EID_SSID; | ||
461 | *pos++ = 0; | ||
462 | |||
463 | len += 2; | ||
464 | |||
465 | if (WARN_ON(left < ie_len)) | ||
466 | return len; | ||
467 | |||
468 | if (ies && ie_len) { | ||
469 | memcpy(pos, ies, ie_len); | ||
470 | len += ie_len; | ||
471 | } | ||
472 | |||
473 | return (u16)len; | ||
474 | } | ||
475 | EXPORT_SYMBOL(iwl_legacy_fill_probe_req); | ||
476 | |||
477 | static void iwl_legacy_bg_abort_scan(struct work_struct *work) | ||
478 | { | ||
479 | struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); | ||
480 | |||
481 | IWL_DEBUG_SCAN(priv, "Abort scan work\n"); | ||
482 | |||
483 | /* We keep scan_check work queued in case when firmware will not | ||
484 | * report back scan completed notification */ | ||
485 | mutex_lock(&priv->mutex); | ||
486 | iwl_legacy_scan_cancel_timeout(priv, 200); | ||
487 | mutex_unlock(&priv->mutex); | ||
488 | } | ||
489 | |||
490 | static void iwl_legacy_bg_scan_completed(struct work_struct *work) | ||
491 | { | ||
492 | struct iwl_priv *priv = | ||
493 | container_of(work, struct iwl_priv, scan_completed); | ||
494 | bool aborted; | ||
495 | |||
496 | IWL_DEBUG_SCAN(priv, "Completed scan.\n"); | ||
497 | |||
498 | cancel_delayed_work(&priv->scan_check); | ||
499 | |||
500 | mutex_lock(&priv->mutex); | ||
501 | |||
502 | aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status); | ||
503 | if (aborted) | ||
504 | IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); | ||
505 | |||
506 | if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) { | ||
507 | IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); | ||
508 | goto out_settings; | ||
509 | } | ||
510 | |||
511 | iwl_legacy_complete_scan(priv, aborted); | ||
512 | |||
513 | out_settings: | ||
514 | /* Can we still talk to firmware ? */ | ||
515 | if (!iwl_legacy_is_ready_rf(priv)) | ||
516 | goto out; | ||
517 | |||
518 | /* | ||
519 | * We do not commit power settings while scan is pending, | ||
520 | * do it now if the settings changed. | ||
521 | */ | ||
522 | iwl_legacy_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false); | ||
523 | iwl_legacy_set_tx_power(priv, priv->tx_power_next, false); | ||
524 | |||
525 | priv->cfg->ops->utils->post_scan(priv); | ||
526 | |||
527 | out: | ||
528 | mutex_unlock(&priv->mutex); | ||
529 | } | ||
530 | |||
531 | void iwl_legacy_setup_scan_deferred_work(struct iwl_priv *priv) | ||
532 | { | ||
533 | INIT_WORK(&priv->scan_completed, iwl_legacy_bg_scan_completed); | ||
534 | INIT_WORK(&priv->abort_scan, iwl_legacy_bg_abort_scan); | ||
535 | INIT_DELAYED_WORK(&priv->scan_check, iwl_legacy_bg_scan_check); | ||
536 | } | ||
537 | EXPORT_SYMBOL(iwl_legacy_setup_scan_deferred_work); | ||
538 | |||
539 | void iwl_legacy_cancel_scan_deferred_work(struct iwl_priv *priv) | ||
540 | { | ||
541 | cancel_work_sync(&priv->abort_scan); | ||
542 | cancel_work_sync(&priv->scan_completed); | ||
543 | |||
544 | if (cancel_delayed_work_sync(&priv->scan_check)) { | ||
545 | mutex_lock(&priv->mutex); | ||
546 | iwl_legacy_force_scan_end(priv); | ||
547 | mutex_unlock(&priv->mutex); | ||
548 | } | ||
549 | } | ||
550 | EXPORT_SYMBOL(iwl_legacy_cancel_scan_deferred_work); | ||