OSDN Git Service

wl1271: Removed wl1271_spi.h and made some functions static
[uclinux-h8/linux.git] / drivers / net / wireless / wl12xx / wl1271_event.c
1 /*
2  * This file is part of wl1271
3  *
4  * Copyright (C) 2008-2009 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 "wl1271.h"
25 #include "wl1271_reg.h"
26 #include "wl1271_io.h"
27 #include "wl1271_event.h"
28 #include "wl1271_ps.h"
29 #include "wl12xx_80211.h"
30
31 static int wl1271_event_scan_complete(struct wl1271 *wl,
32                                       struct event_mailbox *mbox)
33 {
34         int size = sizeof(struct wl12xx_probe_req_template);
35         wl1271_debug(DEBUG_EVENT, "status: 0x%x",
36                      mbox->scheduled_scan_status);
37
38         if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
39                 if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
40                         wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
41                                                 NULL, size);
42                         /* 2.4 GHz band scanned, scan 5 GHz band, pretend
43                          * to the wl1271_cmd_scan function that we are not
44                          * scanning as it checks that.
45                          */
46                         clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
47                         wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
48                                                 wl->scan.active,
49                                                 wl->scan.high_prio,
50                                                 WL1271_SCAN_BAND_5_GHZ,
51                                                 wl->scan.probe_requests);
52                 } else {
53                         if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
54                                 wl1271_cmd_template_set(wl,
55                                                 CMD_TEMPL_CFG_PROBE_REQ_2_4,
56                                                 NULL, size);
57                         else
58                                 wl1271_cmd_template_set(wl,
59                                                 CMD_TEMPL_CFG_PROBE_REQ_5,
60                                                 NULL, size);
61
62                         mutex_unlock(&wl->mutex);
63                         ieee80211_scan_completed(wl->hw, false);
64                         mutex_lock(&wl->mutex);
65                         clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
66                 }
67         }
68         return 0;
69 }
70
71 static int wl1271_event_ps_report(struct wl1271 *wl,
72                                   struct event_mailbox *mbox,
73                                   bool *beacon_loss)
74 {
75         int ret = 0;
76
77         wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
78
79         switch (mbox->ps_status) {
80         case EVENT_ENTER_POWER_SAVE_FAIL:
81                 wl1271_debug(DEBUG_PSM, "PSM entry failed");
82
83                 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
84                         /* remain in active mode */
85                         wl->psm_entry_retry = 0;
86                         break;
87                 }
88
89                 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
90                         wl->psm_entry_retry++;
91                         ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
92                                                  true);
93                 } else {
94                         wl1271_error("PSM entry failed, giving up.\n");
95                         /* FIXME: this may need to be reconsidered. for now it
96                            is not possible to indicate to the mac80211
97                            afterwards that PSM entry failed. To maximize
98                            functionality (receiving data and remaining
99                            associated) make sure that we are in sync with the
100                            AP in regard of PSM mode. */
101                         ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
102                                                  false);
103                         wl->psm_entry_retry = 0;
104                 }
105                 break;
106         case EVENT_ENTER_POWER_SAVE_SUCCESS:
107                 wl->psm_entry_retry = 0;
108
109                 /* enable beacon filtering */
110                 ret = wl1271_acx_beacon_filter_opt(wl, true);
111                 if (ret < 0)
112                         break;
113
114                 /* enable beacon early termination */
115                 ret = wl1271_acx_bet_enable(wl, true);
116                 if (ret < 0)
117                         break;
118
119                 /* go to extremely low power mode */
120                 wl1271_ps_elp_sleep(wl);
121                 if (ret < 0)
122                         break;
123                 break;
124         case EVENT_EXIT_POWER_SAVE_FAIL:
125                 wl1271_debug(DEBUG_PSM, "PSM exit failed");
126
127                 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
128                         wl->psm_entry_retry = 0;
129                         break;
130                 }
131
132                 /* make sure the firmware goes to active mode - the frame to
133                    be sent next will indicate to the AP, that we are active. */
134                 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
135                                          false);
136                 break;
137         case EVENT_EXIT_POWER_SAVE_SUCCESS:
138         default:
139                 break;
140         }
141
142         return ret;
143 }
144
145 static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
146 {
147         wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
148         wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
149         wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
150 }
151
152 static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
153 {
154         int ret;
155         u32 vector;
156         bool beacon_loss = false;
157
158         wl1271_event_mbox_dump(mbox);
159
160         vector = le32_to_cpu(mbox->events_vector);
161         vector &= ~(le32_to_cpu(mbox->events_mask));
162         wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
163
164         if (vector & SCAN_COMPLETE_EVENT_ID) {
165                 ret = wl1271_event_scan_complete(wl, mbox);
166                 if (ret < 0)
167                         return ret;
168         }
169
170         /*
171          * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
172          * filtering) is enabled. Without PSM, the stack will receive all
173          * beacons and can detect beacon loss by itself.
174          */
175         if (vector & BSS_LOSE_EVENT_ID &&
176             test_bit(WL1271_FLAG_PSM, &wl->flags)) {
177                 wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
178
179                 /* indicate to the stack, that beacons have been lost */
180                 beacon_loss = true;
181         }
182
183         if (vector & PS_REPORT_EVENT_ID) {
184                 wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
185                 ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
186                 if (ret < 0)
187                         return ret;
188         }
189
190         if (wl->vif && beacon_loss) {
191                 /* Obviously, it's dangerous to release the mutex while
192                    we are holding many of the variables in the wl struct.
193                    That's why it's done last in the function, and care must
194                    be taken that nothing more is done after this function
195                    returns. */
196                 mutex_unlock(&wl->mutex);
197                 ieee80211_beacon_loss(wl->vif);
198                 mutex_lock(&wl->mutex);
199         }
200
201         return 0;
202 }
203
204 int wl1271_event_unmask(struct wl1271 *wl)
205 {
206         int ret;
207
208         ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
209         if (ret < 0)
210                 return ret;
211
212         return 0;
213 }
214
215 void wl1271_event_mbox_config(struct wl1271 *wl)
216 {
217         wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
218         wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
219
220         wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
221                      wl->mbox_ptr[0], wl->mbox_ptr[1]);
222 }
223
224 int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
225 {
226         struct event_mailbox mbox;
227         int ret;
228
229         wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
230
231         if (mbox_num > 1)
232                 return -EINVAL;
233
234         /* first we read the mbox descriptor */
235         wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
236                     sizeof(struct event_mailbox), false);
237
238         /* process the descriptor */
239         ret = wl1271_event_process(wl, &mbox);
240         if (ret < 0)
241                 return ret;
242
243         /* then we let the firmware know it can go on...*/
244         wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
245
246         return 0;
247 }