diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_event.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_event.c | 99 |
1 files changed, 70 insertions, 29 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index ca52cdec7a8f..25ce2cd5e3f3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c | |||
@@ -26,36 +26,64 @@ | |||
26 | #include "wl1271_io.h" | 26 | #include "wl1271_io.h" |
27 | #include "wl1271_event.h" | 27 | #include "wl1271_event.h" |
28 | #include "wl1271_ps.h" | 28 | #include "wl1271_ps.h" |
29 | #include "wl1271_scan.h" | ||
29 | #include "wl12xx_80211.h" | 30 | #include "wl12xx_80211.h" |
30 | 31 | ||
31 | static int wl1271_event_scan_complete(struct wl1271 *wl, | 32 | void wl1271_pspoll_work(struct work_struct *work) |
32 | struct event_mailbox *mbox) | ||
33 | { | 33 | { |
34 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | 34 | struct delayed_work *dwork; |
35 | mbox->scheduled_scan_status); | 35 | struct wl1271 *wl; |
36 | 36 | ||
37 | if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { | 37 | dwork = container_of(work, struct delayed_work, work); |
38 | if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { | 38 | wl = container_of(dwork, struct wl1271, pspoll_work); |
39 | /* 2.4 GHz band scanned, scan 5 GHz band, pretend | 39 | |
40 | * to the wl1271_cmd_scan function that we are not | 40 | wl1271_debug(DEBUG_EVENT, "pspoll work"); |
41 | * scanning as it checks that. | 41 | |
42 | */ | 42 | mutex_lock(&wl->mutex); |
43 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | 43 | |
44 | /* FIXME: ie missing! */ | 44 | if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags)) |
45 | wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, | 45 | goto out; |
46 | wl->scan.req, | 46 | |
47 | wl->scan.active, | 47 | if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) |
48 | wl->scan.high_prio, | 48 | goto out; |
49 | WL1271_SCAN_BAND_5_GHZ, | 49 | |
50 | wl->scan.probe_requests); | 50 | /* |
51 | } else { | 51 | * if we end up here, then we were in powersave when the pspoll |
52 | mutex_unlock(&wl->mutex); | 52 | * delivery failure occurred, and no-one changed state since, so |
53 | ieee80211_scan_completed(wl->hw, false); | 53 | * we should go back to powersave. |
54 | mutex_lock(&wl->mutex); | 54 | */ |
55 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | 55 | wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true); |
56 | } | 56 | |
57 | out: | ||
58 | mutex_unlock(&wl->mutex); | ||
59 | }; | ||
60 | |||
61 | static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl) | ||
62 | { | ||
63 | int delay = wl->conf.conn.ps_poll_recovery_period; | ||
64 | int ret; | ||
65 | |||
66 | wl->ps_poll_failures++; | ||
67 | if (wl->ps_poll_failures == 1) | ||
68 | wl1271_info("AP with dysfunctional ps-poll, " | ||
69 | "trying to work around it."); | ||
70 | |||
71 | /* force active mode receive data from the AP */ | ||
72 | if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||
73 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true); | ||
74 | if (ret < 0) | ||
75 | return; | ||
76 | set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags); | ||
77 | ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work, | ||
78 | msecs_to_jiffies(delay)); | ||
57 | } | 79 | } |
58 | return 0; | 80 | |
81 | /* | ||
82 | * If already in active mode, lets we should be getting data from | ||
83 | * the AP right away. If we enter PSM too fast after this, and data | ||
84 | * remains on the AP, we will get another event like this, and we'll | ||
85 | * go into active once more. | ||
86 | */ | ||
59 | } | 87 | } |
60 | 88 | ||
61 | static int wl1271_event_ps_report(struct wl1271 *wl, | 89 | static int wl1271_event_ps_report(struct wl1271 *wl, |
@@ -163,9 +191,19 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
163 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); | 191 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); |
164 | 192 | ||
165 | if (vector & SCAN_COMPLETE_EVENT_ID) { | 193 | if (vector & SCAN_COMPLETE_EVENT_ID) { |
166 | ret = wl1271_event_scan_complete(wl, mbox); | 194 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", |
167 | if (ret < 0) | 195 | mbox->scheduled_scan_status); |
168 | return ret; | 196 | |
197 | wl1271_scan_stm(wl); | ||
198 | } | ||
199 | |||
200 | /* disable dynamic PS when requested by the firmware */ | ||
201 | if (vector & SOFT_GEMINI_SENSE_EVENT_ID && | ||
202 | wl->bss_type == BSS_TYPE_STA_BSS) { | ||
203 | if (mbox->soft_gemini_sense_info) | ||
204 | ieee80211_disable_dyn_ps(wl->vif); | ||
205 | else | ||
206 | ieee80211_enable_dyn_ps(wl->vif); | ||
169 | } | 207 | } |
170 | 208 | ||
171 | /* | 209 | /* |
@@ -191,6 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
191 | return ret; | 229 | return ret; |
192 | } | 230 | } |
193 | 231 | ||
232 | if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) | ||
233 | wl1271_event_pspoll_delivery_fail(wl); | ||
234 | |||
194 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { | 235 | if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { |
195 | wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); | 236 | wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); |
196 | if (wl->vif) | 237 | if (wl->vif) |