wireless/wl12xx/wl1251: move TI WLAN modules to a common ti subdirectory
[linux-2.6-block.git] / drivers / net / wireless / ti / wl12xx / testmode.c
1 /*
2  * This file is part of wl1271
3  *
4  * Copyright (C) 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 #include "testmode.h"
24
25 #include <linux/slab.h>
26 #include <net/genetlink.h>
27
28 #include "wl12xx.h"
29 #include "debug.h"
30 #include "acx.h"
31 #include "reg.h"
32 #include "ps.h"
33 #include "io.h"
34
35 #define WL1271_TM_MAX_DATA_LENGTH 1024
36
37 enum wl1271_tm_commands {
38         WL1271_TM_CMD_UNSPEC,
39         WL1271_TM_CMD_TEST,
40         WL1271_TM_CMD_INTERROGATE,
41         WL1271_TM_CMD_CONFIGURE,
42         WL1271_TM_CMD_NVS_PUSH,         /* Not in use. Keep to not break ABI */
43         WL1271_TM_CMD_SET_PLT_MODE,
44         WL1271_TM_CMD_RECOVER,
45         WL1271_TM_CMD_GET_MAC,
46
47         __WL1271_TM_CMD_AFTER_LAST
48 };
49 #define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
50
51 enum wl1271_tm_attrs {
52         WL1271_TM_ATTR_UNSPEC,
53         WL1271_TM_ATTR_CMD_ID,
54         WL1271_TM_ATTR_ANSWER,
55         WL1271_TM_ATTR_DATA,
56         WL1271_TM_ATTR_IE_ID,
57         WL1271_TM_ATTR_PLT_MODE,
58
59         __WL1271_TM_ATTR_AFTER_LAST
60 };
61 #define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
62
63 static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
64         [WL1271_TM_ATTR_CMD_ID] =       { .type = NLA_U32 },
65         [WL1271_TM_ATTR_ANSWER] =       { .type = NLA_U8 },
66         [WL1271_TM_ATTR_DATA] =         { .type = NLA_BINARY,
67                                           .len = WL1271_TM_MAX_DATA_LENGTH },
68         [WL1271_TM_ATTR_IE_ID] =        { .type = NLA_U32 },
69         [WL1271_TM_ATTR_PLT_MODE] =     { .type = NLA_U32 },
70 };
71
72
73 static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
74 {
75         int buf_len, ret, len;
76         struct sk_buff *skb;
77         void *buf;
78         u8 answer = 0;
79
80         wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
81
82         if (!tb[WL1271_TM_ATTR_DATA])
83                 return -EINVAL;
84
85         buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
86         buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
87
88         if (tb[WL1271_TM_ATTR_ANSWER])
89                 answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
90
91         if (buf_len > sizeof(struct wl1271_command))
92                 return -EMSGSIZE;
93
94         mutex_lock(&wl->mutex);
95
96         if (wl->state == WL1271_STATE_OFF) {
97                 ret = -EINVAL;
98                 goto out;
99         }
100
101         ret = wl1271_ps_elp_wakeup(wl);
102         if (ret < 0)
103                 goto out;
104
105         ret = wl1271_cmd_test(wl, buf, buf_len, answer);
106         if (ret < 0) {
107                 wl1271_warning("testmode cmd test failed: %d", ret);
108                 goto out_sleep;
109         }
110
111         if (answer) {
112                 len = nla_total_size(buf_len);
113                 skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
114                 if (!skb) {
115                         ret = -ENOMEM;
116                         goto out_sleep;
117                 }
118
119                 NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
120                 ret = cfg80211_testmode_reply(skb);
121                 if (ret < 0)
122                         goto out_sleep;
123         }
124
125 out_sleep:
126         wl1271_ps_elp_sleep(wl);
127 out:
128         mutex_unlock(&wl->mutex);
129
130         return ret;
131
132 nla_put_failure:
133         kfree_skb(skb);
134         ret = -EMSGSIZE;
135         goto out_sleep;
136 }
137
138 static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
139 {
140         int ret;
141         struct wl1271_command *cmd;
142         struct sk_buff *skb;
143         u8 ie_id;
144
145         wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
146
147         if (!tb[WL1271_TM_ATTR_IE_ID])
148                 return -EINVAL;
149
150         ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
151
152         mutex_lock(&wl->mutex);
153
154         if (wl->state == WL1271_STATE_OFF) {
155                 ret = -EINVAL;
156                 goto out;
157         }
158
159         ret = wl1271_ps_elp_wakeup(wl);
160         if (ret < 0)
161                 goto out;
162
163         cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
164         if (!cmd) {
165                 ret = -ENOMEM;
166                 goto out_sleep;
167         }
168
169         ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
170         if (ret < 0) {
171                 wl1271_warning("testmode cmd interrogate failed: %d", ret);
172                 goto out_free;
173         }
174
175         skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
176         if (!skb) {
177                 ret = -ENOMEM;
178                 goto out_free;
179         }
180
181         NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
182         ret = cfg80211_testmode_reply(skb);
183         if (ret < 0)
184                 goto out_free;
185
186 out_free:
187         kfree(cmd);
188 out_sleep:
189         wl1271_ps_elp_sleep(wl);
190 out:
191         mutex_unlock(&wl->mutex);
192
193         return ret;
194
195 nla_put_failure:
196         kfree_skb(skb);
197         ret = -EMSGSIZE;
198         goto out_free;
199 }
200
201 static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
202 {
203         int buf_len, ret;
204         void *buf;
205         u8 ie_id;
206
207         wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
208
209         if (!tb[WL1271_TM_ATTR_DATA])
210                 return -EINVAL;
211         if (!tb[WL1271_TM_ATTR_IE_ID])
212                 return -EINVAL;
213
214         ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
215         buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
216         buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
217
218         if (buf_len > sizeof(struct wl1271_command))
219                 return -EMSGSIZE;
220
221         mutex_lock(&wl->mutex);
222         ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
223         mutex_unlock(&wl->mutex);
224
225         if (ret < 0) {
226                 wl1271_warning("testmode cmd configure failed: %d", ret);
227                 return ret;
228         }
229
230         return 0;
231 }
232
233 static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
234 {
235         u32 val;
236         int ret;
237
238         wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
239
240         if (!tb[WL1271_TM_ATTR_PLT_MODE])
241                 return -EINVAL;
242
243         val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
244
245         switch (val) {
246         case 0:
247                 ret = wl1271_plt_stop(wl);
248                 break;
249         case 1:
250                 ret = wl1271_plt_start(wl);
251                 break;
252         default:
253                 ret = -EINVAL;
254                 break;
255         }
256
257         return ret;
258 }
259
260 static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
261 {
262         wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
263
264         wl12xx_queue_recovery_work(wl);
265
266         return 0;
267 }
268
269 static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
270 {
271         struct sk_buff *skb;
272         u8 mac_addr[ETH_ALEN];
273         int ret = 0;
274
275         mutex_lock(&wl->mutex);
276
277         if (!wl->plt) {
278                 ret = -EINVAL;
279                 goto out;
280         }
281
282         if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
283                 ret = -EOPNOTSUPP;
284                 goto out;
285         }
286
287         mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
288         mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
289         mac_addr[2] = (u8) wl->fuse_oui_addr;
290         mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
291         mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
292         mac_addr[5] = (u8) wl->fuse_nic_addr;
293
294         skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
295         if (!skb) {
296                 ret = -ENOMEM;
297                 goto out;
298         }
299
300         NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr);
301         ret = cfg80211_testmode_reply(skb);
302         if (ret < 0)
303                 goto out;
304
305 out:
306         mutex_unlock(&wl->mutex);
307         return ret;
308
309 nla_put_failure:
310         kfree_skb(skb);
311         ret = -EMSGSIZE;
312         goto out;
313 }
314
315 int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
316 {
317         struct wl1271 *wl = hw->priv;
318         struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
319         int err;
320
321         err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
322         if (err)
323                 return err;
324
325         if (!tb[WL1271_TM_ATTR_CMD_ID])
326                 return -EINVAL;
327
328         switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
329         case WL1271_TM_CMD_TEST:
330                 return wl1271_tm_cmd_test(wl, tb);
331         case WL1271_TM_CMD_INTERROGATE:
332                 return wl1271_tm_cmd_interrogate(wl, tb);
333         case WL1271_TM_CMD_CONFIGURE:
334                 return wl1271_tm_cmd_configure(wl, tb);
335         case WL1271_TM_CMD_SET_PLT_MODE:
336                 return wl1271_tm_cmd_set_plt_mode(wl, tb);
337         case WL1271_TM_CMD_RECOVER:
338                 return wl1271_tm_cmd_recover(wl, tb);
339         case WL1271_TM_CMD_GET_MAC:
340                 return wl12xx_tm_cmd_get_mac(wl, tb);
341         default:
342                 return -EOPNOTSUPP;
343         }
344 }