Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
testmode.c
Go to the documentation of this file.
1 /*
2  * This file is part of wl1271
3  *
4  * Copyright (C) 2010 Nokia Corporation
5  *
6  * Contact: Luciano Coelho <[email protected]>
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 "wlcore.h"
29 #include "debug.h"
30 #include "acx.h"
31 #include "ps.h"
32 #include "io.h"
33 
34 #define WL1271_TM_MAX_DATA_LENGTH 1024
35 
41  WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */
43  WL1271_TM_CMD_RECOVER, /* Not in use. Keep to not break ABI */
45 
47 };
48 #define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
49 
57 
59 };
60 #define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
61 
62 static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
63  [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 },
64  [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 },
65  [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY,
67  [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 },
68  [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 },
69 };
70 
71 
72 static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
73 {
74  int buf_len, ret, len;
75  struct sk_buff *skb;
76  void *buf;
77  u8 answer = 0;
78 
79  wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
80 
81  if (!tb[WL1271_TM_ATTR_DATA])
82  return -EINVAL;
83 
84  buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
85  buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
86 
87  if (tb[WL1271_TM_ATTR_ANSWER])
88  answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
89 
90  if (buf_len > sizeof(struct wl1271_command))
91  return -EMSGSIZE;
92 
93  mutex_lock(&wl->mutex);
94 
95  if (unlikely(wl->state != WLCORE_STATE_ON)) {
96  ret = -EINVAL;
97  goto out;
98  }
99 
100  ret = wl1271_ps_elp_wakeup(wl);
101  if (ret < 0)
102  goto out;
103 
104  ret = wl1271_cmd_test(wl, buf, buf_len, answer);
105  if (ret < 0) {
106  wl1271_warning("testmode cmd test failed: %d", ret);
107  goto out_sleep;
108  }
109 
110  if (answer) {
111  /* If we got bip calibration answer print radio status */
112  struct wl1271_cmd_cal_p2g *params =
113  (struct wl1271_cmd_cal_p2g *) buf;
114 
116 
117  if (params->test.id == TEST_CMD_P2G_CAL &&
118  radio_status < 0)
119  wl1271_warning("testmode cmd: radio status=%d",
120  radio_status);
121  else
122  wl1271_info("testmode cmd: radio status=%d",
123  radio_status);
124 
125  len = nla_total_size(buf_len);
126  skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
127  if (!skb) {
128  ret = -ENOMEM;
129  goto out_sleep;
130  }
131 
132  if (nla_put(skb, WL1271_TM_ATTR_DATA, buf_len, buf)) {
133  kfree_skb(skb);
134  ret = -EMSGSIZE;
135  goto out_sleep;
136  }
137 
138  ret = cfg80211_testmode_reply(skb);
139  if (ret < 0)
140  goto out_sleep;
141  }
142 
143 out_sleep:
145 out:
146  mutex_unlock(&wl->mutex);
147 
148  return ret;
149 }
150 
151 static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
152 {
153  int ret;
154  struct wl1271_command *cmd;
155  struct sk_buff *skb;
156  u8 ie_id;
157 
158  wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
159 
160  if (!tb[WL1271_TM_ATTR_IE_ID])
161  return -EINVAL;
162 
163  ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
164 
165  mutex_lock(&wl->mutex);
166 
167  if (unlikely(wl->state != WLCORE_STATE_ON)) {
168  ret = -EINVAL;
169  goto out;
170  }
171 
172  ret = wl1271_ps_elp_wakeup(wl);
173  if (ret < 0)
174  goto out;
175 
176  cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
177  if (!cmd) {
178  ret = -ENOMEM;
179  goto out_sleep;
180  }
181 
182  ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
183  if (ret < 0) {
184  wl1271_warning("testmode cmd interrogate failed: %d", ret);
185  goto out_free;
186  }
187 
188  skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
189  if (!skb) {
190  ret = -ENOMEM;
191  goto out_free;
192  }
193 
194  if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd)) {
195  kfree_skb(skb);
196  ret = -EMSGSIZE;
197  goto out_free;
198  }
199 
200  ret = cfg80211_testmode_reply(skb);
201  if (ret < 0)
202  goto out_free;
203 
204 out_free:
205  kfree(cmd);
206 out_sleep:
208 out:
209  mutex_unlock(&wl->mutex);
210 
211  return ret;
212 }
213 
214 static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
215 {
216  int buf_len, ret;
217  void *buf;
218  u8 ie_id;
219 
220  wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
221 
222  if (!tb[WL1271_TM_ATTR_DATA])
223  return -EINVAL;
224  if (!tb[WL1271_TM_ATTR_IE_ID])
225  return -EINVAL;
226 
227  ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
228  buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
229  buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
230 
231  if (buf_len > sizeof(struct wl1271_command))
232  return -EMSGSIZE;
233 
234  mutex_lock(&wl->mutex);
235  ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
236  mutex_unlock(&wl->mutex);
237 
238  if (ret < 0) {
239  wl1271_warning("testmode cmd configure failed: %d", ret);
240  return ret;
241  }
242 
243  return 0;
244 }
245 
246 static int wl1271_tm_detect_fem(struct wl1271 *wl, struct nlattr *tb[])
247 {
248  /* return FEM type */
249  int ret, len;
250  struct sk_buff *skb;
251 
252  ret = wl1271_plt_start(wl, PLT_FEM_DETECT);
253  if (ret < 0)
254  goto out;
255 
256  mutex_lock(&wl->mutex);
257 
258  len = nla_total_size(sizeof(wl->fem_manuf));
259  skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
260  if (!skb) {
261  ret = -ENOMEM;
262  goto out_mutex;
263  }
264 
265  if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(wl->fem_manuf),
266  &wl->fem_manuf)) {
267  kfree_skb(skb);
268  ret = -EMSGSIZE;
269  goto out_mutex;
270  }
271 
272  ret = cfg80211_testmode_reply(skb);
273 
274 out_mutex:
275  mutex_unlock(&wl->mutex);
276 
277  /* We always stop plt after DETECT mode */
278  wl1271_plt_stop(wl);
279 out:
280  return ret;
281 }
282 
283 static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
284 {
285  u32 val;
286  int ret;
287 
288  wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
289 
290  if (!tb[WL1271_TM_ATTR_PLT_MODE])
291  return -EINVAL;
292 
293  val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
294 
295  switch (val) {
296  case PLT_OFF:
297  ret = wl1271_plt_stop(wl);
298  break;
299  case PLT_ON:
300  ret = wl1271_plt_start(wl, PLT_ON);
301  break;
302  case PLT_FEM_DETECT:
303  ret = wl1271_tm_detect_fem(wl, tb);
304  break;
305  default:
306  ret = -EINVAL;
307  break;
308  }
309 
310  return ret;
311 }
312 
313 static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
314 {
315  struct sk_buff *skb;
317  int ret = 0;
318 
319  mutex_lock(&wl->mutex);
320 
321  if (!wl->plt) {
322  ret = -EINVAL;
323  goto out;
324  }
325 
326  if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
327  ret = -EOPNOTSUPP;
328  goto out;
329  }
330 
331  mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
332  mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
333  mac_addr[2] = (u8) wl->fuse_oui_addr;
334  mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
335  mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
336  mac_addr[5] = (u8) wl->fuse_nic_addr;
337 
338  skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
339  if (!skb) {
340  ret = -ENOMEM;
341  goto out;
342  }
343 
344  if (nla_put(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr)) {
345  kfree_skb(skb);
346  ret = -EMSGSIZE;
347  goto out;
348  }
349 
350  ret = cfg80211_testmode_reply(skb);
351  if (ret < 0)
352  goto out;
353 
354 out:
355  mutex_unlock(&wl->mutex);
356  return ret;
357 }
358 
359 int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
360 {
361  struct wl1271 *wl = hw->priv;
362  struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
363  int err;
364 
365  err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
366  if (err)
367  return err;
368 
369  if (!tb[WL1271_TM_ATTR_CMD_ID])
370  return -EINVAL;
371 
372  switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
373  case WL1271_TM_CMD_TEST:
374  return wl1271_tm_cmd_test(wl, tb);
376  return wl1271_tm_cmd_interrogate(wl, tb);
378  return wl1271_tm_cmd_configure(wl, tb);
380  return wl1271_tm_cmd_set_plt_mode(wl, tb);
382  return wl12xx_tm_cmd_get_mac(wl, tb);
383  default:
384  return -EOPNOTSUPP;
385  }
386 }