diff options
author | Kalle Valo <kalle.valo@nokia.com> | 2009-07-21 07:25:53 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-24 15:05:29 -0400 |
commit | f298c282a5233126ffe6385c02a9e79f695bed0f (patch) | |
tree | f4500c35caa1dffd355da6104e408c7f521f2b86 /drivers/net/wireless | |
parent | f974cfdd8112a081fb1a402bf77835f28f37fcad (diff) |
wl1251: remove accidentally added wl1251_netlink.c
Commit "wl1251: add wl1251 prefix to all 1251 files" accidentally added
wl1251_netlink.c which contains a private netlink interface.
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_netlink.c | 679 |
1 files changed, 0 insertions, 679 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c deleted file mode 100644 index 67d3d5a3b519..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ /dev/null | |||
@@ -1,679 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@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 "wl1251_netlink.h" | ||
24 | |||
25 | #include <linux/mutex.h> | ||
26 | #include <linux/socket.h> | ||
27 | #include <net/net_namespace.h> | ||
28 | #include <net/sock.h> | ||
29 | #include <net/genetlink.h> | ||
30 | #include <net/wireless.h> | ||
31 | #include <net/mac80211.h> | ||
32 | |||
33 | #include "wl1251.h" | ||
34 | #include "wl1251_spi.h" | ||
35 | #include "wl1251_acx.h" | ||
36 | |||
37 | /* FIXME: this should be changed as soon as user space catches up */ | ||
38 | #define WL1251_NL_NAME "wl1251" | ||
39 | #define WL1251_NL_VERSION 1 | ||
40 | |||
41 | #define WL1251_MAX_TEST_LENGTH 1024 | ||
42 | #define WL1251_MAX_NVS_LENGTH 1024 | ||
43 | |||
44 | enum wl1251_nl_commands { | ||
45 | WL1251_NL_CMD_UNSPEC, | ||
46 | WL1251_NL_CMD_TEST, | ||
47 | WL1251_NL_CMD_INTERROGATE, | ||
48 | WL1251_NL_CMD_CONFIGURE, | ||
49 | WL1251_NL_CMD_PHY_REG_READ, | ||
50 | WL1251_NL_CMD_NVS_PUSH, | ||
51 | WL1251_NL_CMD_REG_WRITE, | ||
52 | WL1251_NL_CMD_REG_READ, | ||
53 | WL1251_NL_CMD_SET_PLT_MODE, | ||
54 | |||
55 | __WL1251_NL_CMD_AFTER_LAST | ||
56 | }; | ||
57 | #define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1) | ||
58 | |||
59 | enum wl1251_nl_attrs { | ||
60 | WL1251_NL_ATTR_UNSPEC, | ||
61 | WL1251_NL_ATTR_IFNAME, | ||
62 | WL1251_NL_ATTR_CMD_TEST_PARAM, | ||
63 | WL1251_NL_ATTR_CMD_TEST_ANSWER, | ||
64 | WL1251_NL_ATTR_CMD_IE, | ||
65 | WL1251_NL_ATTR_CMD_IE_LEN, | ||
66 | WL1251_NL_ATTR_CMD_IE_BUFFER, | ||
67 | WL1251_NL_ATTR_CMD_IE_ANSWER, | ||
68 | WL1251_NL_ATTR_REG_ADDR, | ||
69 | WL1251_NL_ATTR_REG_VAL, | ||
70 | WL1251_NL_ATTR_NVS_BUFFER, | ||
71 | WL1251_NL_ATTR_NVS_LEN, | ||
72 | WL1251_NL_ATTR_PLT_MODE, | ||
73 | |||
74 | __WL1251_NL_ATTR_AFTER_LAST | ||
75 | }; | ||
76 | #define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1) | ||
77 | |||
78 | static struct genl_family wl1251_nl_family = { | ||
79 | .id = GENL_ID_GENERATE, | ||
80 | .name = WL1251_NL_NAME, | ||
81 | .hdrsize = 0, | ||
82 | .version = WL1251_NL_VERSION, | ||
83 | .maxattr = WL1251_NL_ATTR_MAX, | ||
84 | }; | ||
85 | |||
86 | static struct net_device *ifname_to_netdev(struct net *net, | ||
87 | struct genl_info *info) | ||
88 | { | ||
89 | char *ifname; | ||
90 | |||
91 | if (!info->attrs[WL1251_NL_ATTR_IFNAME]) | ||
92 | return NULL; | ||
93 | |||
94 | ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]); | ||
95 | |||
96 | wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname); | ||
97 | |||
98 | return dev_get_by_name(net, ifname); | ||
99 | } | ||
100 | |||
101 | static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info) | ||
102 | { | ||
103 | struct net_device *netdev; | ||
104 | struct wireless_dev *wdev; | ||
105 | struct wiphy *wiphy; | ||
106 | struct ieee80211_hw *hw; | ||
107 | |||
108 | netdev = ifname_to_netdev(net, info); | ||
109 | if (netdev == NULL) { | ||
110 | wl1251_error("Wrong interface"); | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
114 | wdev = netdev->ieee80211_ptr; | ||
115 | if (wdev == NULL) { | ||
116 | wl1251_error("ieee80211_ptr is NULL"); | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | wiphy = wdev->wiphy; | ||
121 | if (wiphy == NULL) { | ||
122 | wl1251_error("wiphy is NULL"); | ||
123 | return NULL; | ||
124 | } | ||
125 | |||
126 | hw = wiphy_priv(wiphy); | ||
127 | if (hw == NULL) { | ||
128 | wl1251_error("hw is NULL"); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | dev_put(netdev); | ||
133 | |||
134 | return hw->priv; | ||
135 | } | ||
136 | |||
137 | static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) | ||
138 | { | ||
139 | struct wl1251 *wl; | ||
140 | struct wl1251_command *cmd; | ||
141 | char *buf; | ||
142 | int buf_len, ret, cmd_len; | ||
143 | u8 answer; | ||
144 | |||
145 | if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]) | ||
146 | return -EINVAL; | ||
147 | |||
148 | wl = ifname_to_wl1251(&init_net, info); | ||
149 | if (wl == NULL) { | ||
150 | wl1251_error("wl1251 not found"); | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | |||
154 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
155 | if (!cmd) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); | ||
159 | buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); | ||
160 | answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]); | ||
161 | |||
162 | cmd->header.id = CMD_TEST; | ||
163 | memcpy(cmd->parameters, buf, buf_len); | ||
164 | cmd_len = sizeof(struct wl1251_cmd_header) + buf_len; | ||
165 | |||
166 | mutex_lock(&wl->mutex); | ||
167 | ret = wl1251_cmd_test(wl, cmd, cmd_len, answer); | ||
168 | mutex_unlock(&wl->mutex); | ||
169 | |||
170 | if (ret < 0) { | ||
171 | wl1251_error("%s() failed", __func__); | ||
172 | goto out; | ||
173 | } | ||
174 | |||
175 | if (answer) { | ||
176 | struct sk_buff *msg; | ||
177 | void *hdr; | ||
178 | |||
179 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
180 | if (!msg) { | ||
181 | ret = -ENOMEM; | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, | ||
186 | &wl1251_nl_family, 0, WL1251_NL_CMD_TEST); | ||
187 | if (IS_ERR(hdr)) { | ||
188 | ret = PTR_ERR(hdr); | ||
189 | goto nla_put_failure; | ||
190 | } | ||
191 | |||
192 | NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, | ||
193 | nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); | ||
194 | NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER, | ||
195 | sizeof(*cmd), cmd); | ||
196 | |||
197 | ret = genlmsg_end(msg, hdr); | ||
198 | if (ret < 0) { | ||
199 | wl1251_error("%s() failed", __func__); | ||
200 | goto nla_put_failure; | ||
201 | } | ||
202 | |||
203 | wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); | ||
204 | ret = genlmsg_reply(msg, info); | ||
205 | goto out; | ||
206 | |||
207 | nla_put_failure: | ||
208 | nlmsg_free(msg); | ||
209 | } else | ||
210 | wl1251_debug(DEBUG_NETLINK, "TEST cmd sent"); | ||
211 | |||
212 | out: | ||
213 | kfree(cmd); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info) | ||
218 | { | ||
219 | struct wl1251 *wl; | ||
220 | struct sk_buff *msg; | ||
221 | int ret = -ENOBUFS, cmd_ie, cmd_ie_len; | ||
222 | struct wl1251_command *cmd; | ||
223 | void *hdr; | ||
224 | |||
225 | if (!info->attrs[WL1251_NL_ATTR_CMD_IE]) | ||
226 | return -EINVAL; | ||
227 | |||
228 | if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) | ||
229 | return -EINVAL; | ||
230 | |||
231 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
232 | if (!cmd) | ||
233 | return -ENOMEM; | ||
234 | |||
235 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
236 | if (!msg) | ||
237 | return -ENOMEM; | ||
238 | |||
239 | wl = ifname_to_wl1251(&init_net, info); | ||
240 | if (wl == NULL) { | ||
241 | wl1251_error("wl1251 not found"); | ||
242 | ret = -EINVAL; | ||
243 | goto nla_put_failure; | ||
244 | } | ||
245 | |||
246 | /* acx id */ | ||
247 | cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]); | ||
248 | |||
249 | /* maximum length of acx, including all headers */ | ||
250 | cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); | ||
251 | |||
252 | wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", | ||
253 | cmd_ie, cmd_ie_len); | ||
254 | |||
255 | mutex_lock(&wl->mutex); | ||
256 | ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); | ||
257 | mutex_unlock(&wl->mutex); | ||
258 | |||
259 | if (ret < 0) { | ||
260 | wl1251_error("%s() failed", __func__); | ||
261 | goto nla_put_failure; | ||
262 | } | ||
263 | |||
264 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, | ||
265 | &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE); | ||
266 | if (IS_ERR(hdr)) { | ||
267 | ret = PTR_ERR(hdr); | ||
268 | goto nla_put_failure; | ||
269 | } | ||
270 | |||
271 | NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, | ||
272 | nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); | ||
273 | NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); | ||
274 | |||
275 | ret = genlmsg_end(msg, hdr); | ||
276 | if (ret < 0) { | ||
277 | wl1251_error("%s() failed", __func__); | ||
278 | goto nla_put_failure; | ||
279 | } | ||
280 | |||
281 | kfree(cmd); | ||
282 | return genlmsg_reply(msg, info); | ||
283 | |||
284 | nla_put_failure: | ||
285 | kfree(cmd); | ||
286 | nlmsg_free(msg); | ||
287 | |||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info) | ||
292 | { | ||
293 | int ret = 0, cmd_ie_len, acx_len; | ||
294 | struct acx_header *acx = NULL; | ||
295 | struct sk_buff *msg; | ||
296 | struct wl1251 *wl; | ||
297 | void *cmd_ie; | ||
298 | u16 *id; | ||
299 | |||
300 | if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]) | ||
301 | return -EINVAL; | ||
302 | |||
303 | if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) | ||
304 | return -EINVAL; | ||
305 | |||
306 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
307 | if (!msg) | ||
308 | return -ENOMEM; | ||
309 | |||
310 | wl = ifname_to_wl1251(&init_net, info); | ||
311 | if (wl == NULL) { | ||
312 | wl1251_error("wl1251 not found"); | ||
313 | ret = -EINVAL; | ||
314 | goto nla_put_failure; | ||
315 | } | ||
316 | |||
317 | /* contains the acx header but not the cmd header */ | ||
318 | cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]); | ||
319 | |||
320 | cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); | ||
321 | |||
322 | /* acx id is in the first two bytes */ | ||
323 | id = cmd_ie; | ||
324 | |||
325 | /* need to add acx_header before cmd_ie, so create a new command */ | ||
326 | acx_len = sizeof(struct acx_header) + cmd_ie_len; | ||
327 | acx = kzalloc(acx_len, GFP_KERNEL); | ||
328 | if (!acx) { | ||
329 | ret = -ENOMEM; | ||
330 | goto nla_put_failure; | ||
331 | } | ||
332 | |||
333 | /* copy the acx header and the payload */ | ||
334 | memcpy(&acx->id, cmd_ie, cmd_ie_len); | ||
335 | |||
336 | mutex_lock(&wl->mutex); | ||
337 | ret = wl1251_cmd_configure(wl, *id, acx, acx_len); | ||
338 | mutex_unlock(&wl->mutex); | ||
339 | |||
340 | if (ret < 0) { | ||
341 | wl1251_error("%s() failed", __func__); | ||
342 | goto nla_put_failure; | ||
343 | } | ||
344 | |||
345 | wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); | ||
346 | |||
347 | nla_put_failure: | ||
348 | kfree(acx); | ||
349 | nlmsg_free(msg); | ||
350 | |||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) | ||
355 | { | ||
356 | struct wl1251 *wl; | ||
357 | struct sk_buff *msg; | ||
358 | u32 reg_addr, *reg_value = NULL; | ||
359 | int ret = 0; | ||
360 | void *hdr; | ||
361 | |||
362 | if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) | ||
363 | return -EINVAL; | ||
364 | |||
365 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
366 | if (!msg) | ||
367 | return -ENOMEM; | ||
368 | |||
369 | wl = ifname_to_wl1251(&init_net, info); | ||
370 | if (wl == NULL) { | ||
371 | wl1251_error("wl1251 not found"); | ||
372 | ret = -EINVAL; | ||
373 | goto nla_put_failure; | ||
374 | } | ||
375 | |||
376 | reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL); | ||
377 | if (!reg_value) { | ||
378 | ret = -ENOMEM; | ||
379 | goto nla_put_failure; | ||
380 | } | ||
381 | |||
382 | reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); | ||
383 | |||
384 | wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); | ||
385 | |||
386 | mutex_lock(&wl->mutex); | ||
387 | ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value, | ||
388 | sizeof(*reg_value)); | ||
389 | mutex_unlock(&wl->mutex); | ||
390 | |||
391 | if (ret < 0) { | ||
392 | wl1251_error("%s() failed", __func__); | ||
393 | goto nla_put_failure; | ||
394 | } | ||
395 | |||
396 | |||
397 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, | ||
398 | &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); | ||
399 | if (IS_ERR(hdr)) { | ||
400 | ret = PTR_ERR(hdr); | ||
401 | goto nla_put_failure; | ||
402 | } | ||
403 | |||
404 | NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, | ||
405 | nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); | ||
406 | |||
407 | NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value); | ||
408 | |||
409 | ret = genlmsg_end(msg, hdr); | ||
410 | if (ret < 0) { | ||
411 | wl1251_error("%s() failed", __func__); | ||
412 | goto nla_put_failure; | ||
413 | } | ||
414 | |||
415 | kfree(reg_value); | ||
416 | |||
417 | return genlmsg_reply(msg, info); | ||
418 | |||
419 | nla_put_failure: | ||
420 | nlmsg_free(msg); | ||
421 | kfree(reg_value); | ||
422 | |||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) | ||
427 | { | ||
428 | struct wl1251 *wl; | ||
429 | int ret = 0; | ||
430 | |||
431 | if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER]) | ||
432 | return -EINVAL; | ||
433 | |||
434 | if (!info->attrs[WL1251_NL_ATTR_NVS_LEN]) | ||
435 | return -EINVAL; | ||
436 | |||
437 | wl = ifname_to_wl1251(&init_net, info); | ||
438 | if (wl == NULL) { | ||
439 | wl1251_error("wl1251 not found"); | ||
440 | return -EINVAL; | ||
441 | } | ||
442 | |||
443 | mutex_lock(&wl->mutex); | ||
444 | wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]); | ||
445 | if (wl->nvs_len % 4) { | ||
446 | wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len); | ||
447 | ret = -EILSEQ; | ||
448 | goto out; | ||
449 | } | ||
450 | |||
451 | /* If we already have an NVS, we should free it */ | ||
452 | kfree(wl->nvs); | ||
453 | |||
454 | wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); | ||
455 | if (wl->nvs == NULL) { | ||
456 | wl1251_error("Can't allocate NVS"); | ||
457 | ret = -ENOMEM; | ||
458 | goto out; | ||
459 | } | ||
460 | |||
461 | memcpy(wl->nvs, | ||
462 | nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]), | ||
463 | wl->nvs_len); | ||
464 | |||
465 | wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", | ||
466 | wl->nvs_len); | ||
467 | |||
468 | out: | ||
469 | mutex_unlock(&wl->mutex); | ||
470 | |||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info) | ||
475 | { | ||
476 | struct wl1251 *wl; | ||
477 | u32 addr, val; | ||
478 | int ret = 0; | ||
479 | struct sk_buff *msg; | ||
480 | void *hdr; | ||
481 | |||
482 | if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) | ||
483 | return -EINVAL; | ||
484 | |||
485 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
486 | if (!msg) | ||
487 | return -ENOMEM; | ||
488 | |||
489 | wl = ifname_to_wl1251(&init_net, info); | ||
490 | if (wl == NULL) { | ||
491 | wl1251_error("wl1251 not found"); | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); | ||
496 | |||
497 | mutex_lock(&wl->mutex); | ||
498 | val = wl1251_reg_read32(wl, addr); | ||
499 | mutex_unlock(&wl->mutex); | ||
500 | |||
501 | hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, | ||
502 | &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); | ||
503 | if (IS_ERR(hdr)) { | ||
504 | ret = PTR_ERR(hdr); | ||
505 | goto nla_put_failure; | ||
506 | } | ||
507 | |||
508 | NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, | ||
509 | nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); | ||
510 | |||
511 | NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val); | ||
512 | |||
513 | ret = genlmsg_end(msg, hdr); | ||
514 | if (ret < 0) { | ||
515 | wl1251_error("%s() failed", __func__); | ||
516 | goto nla_put_failure; | ||
517 | } | ||
518 | |||
519 | return genlmsg_reply(msg, info); | ||
520 | |||
521 | nla_put_failure: | ||
522 | nlmsg_free(msg); | ||
523 | |||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info) | ||
528 | { | ||
529 | struct wl1251 *wl; | ||
530 | u32 addr, val; | ||
531 | |||
532 | if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) | ||
533 | return -EINVAL; | ||
534 | |||
535 | if (!info->attrs[WL1251_NL_ATTR_REG_VAL]) | ||
536 | return -EINVAL; | ||
537 | |||
538 | wl = ifname_to_wl1251(&init_net, info); | ||
539 | if (wl == NULL) { | ||
540 | wl1251_error("wl1251 not found"); | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | |||
544 | addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); | ||
545 | val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]); | ||
546 | |||
547 | mutex_lock(&wl->mutex); | ||
548 | wl1251_reg_write32(wl, addr, val); | ||
549 | mutex_unlock(&wl->mutex); | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) | ||
555 | { | ||
556 | struct wl1251 *wl; | ||
557 | u32 val; | ||
558 | int ret; | ||
559 | |||
560 | if (!info->attrs[WL1251_NL_ATTR_PLT_MODE]) | ||
561 | return -EINVAL; | ||
562 | |||
563 | wl = ifname_to_wl1251(&init_net, info); | ||
564 | if (wl == NULL) { | ||
565 | wl1251_error("wl1251 not found"); | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | |||
569 | val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]); | ||
570 | |||
571 | switch (val) { | ||
572 | case 0: | ||
573 | ret = wl1251_plt_stop(wl); | ||
574 | break; | ||
575 | case 1: | ||
576 | ret = wl1251_plt_start(wl); | ||
577 | break; | ||
578 | default: | ||
579 | ret = -EINVAL; | ||
580 | break; | ||
581 | } | ||
582 | |||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = { | ||
587 | [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, | ||
588 | .len = IFNAMSIZ-1 }, | ||
589 | [WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, | ||
590 | .len = WL1251_MAX_TEST_LENGTH }, | ||
591 | [WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, | ||
592 | [WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, | ||
593 | [WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, | ||
594 | [WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, | ||
595 | .len = WL1251_MAX_TEST_LENGTH }, | ||
596 | [WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, | ||
597 | .len = WL1251_MAX_TEST_LENGTH }, | ||
598 | [WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, | ||
599 | [WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, | ||
600 | [WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, | ||
601 | .len = WL1251_MAX_NVS_LENGTH }, | ||
602 | [WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, | ||
603 | [WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, | ||
604 | }; | ||
605 | |||
606 | static struct genl_ops wl1251_nl_ops[] = { | ||
607 | { | ||
608 | .cmd = WL1251_NL_CMD_TEST, | ||
609 | .doit = wl1251_nl_test_cmd, | ||
610 | .policy = wl1251_nl_policy, | ||
611 | .flags = GENL_ADMIN_PERM, | ||
612 | }, | ||
613 | { | ||
614 | .cmd = WL1251_NL_CMD_INTERROGATE, | ||
615 | .doit = wl1251_nl_interrogate, | ||
616 | .policy = wl1251_nl_policy, | ||
617 | .flags = GENL_ADMIN_PERM, | ||
618 | }, | ||
619 | { | ||
620 | .cmd = WL1251_NL_CMD_CONFIGURE, | ||
621 | .doit = wl1251_nl_configure, | ||
622 | .policy = wl1251_nl_policy, | ||
623 | .flags = GENL_ADMIN_PERM, | ||
624 | }, | ||
625 | { | ||
626 | .cmd = WL1251_NL_CMD_PHY_REG_READ, | ||
627 | .doit = wl1251_nl_phy_reg_read, | ||
628 | .policy = wl1251_nl_policy, | ||
629 | .flags = GENL_ADMIN_PERM, | ||
630 | }, | ||
631 | { | ||
632 | .cmd = WL1251_NL_CMD_NVS_PUSH, | ||
633 | .doit = wl1251_nl_nvs_push, | ||
634 | .policy = wl1251_nl_policy, | ||
635 | .flags = GENL_ADMIN_PERM, | ||
636 | }, | ||
637 | { | ||
638 | .cmd = WL1251_NL_CMD_REG_WRITE, | ||
639 | .doit = wl1251_nl_reg_write, | ||
640 | .policy = wl1251_nl_policy, | ||
641 | .flags = GENL_ADMIN_PERM, | ||
642 | }, | ||
643 | { | ||
644 | .cmd = WL1251_NL_CMD_REG_READ, | ||
645 | .doit = wl1251_nl_reg_read, | ||
646 | .policy = wl1251_nl_policy, | ||
647 | .flags = GENL_ADMIN_PERM, | ||
648 | }, | ||
649 | { | ||
650 | .cmd = WL1251_NL_CMD_SET_PLT_MODE, | ||
651 | .doit = wl1251_nl_set_plt_mode, | ||
652 | .policy = wl1251_nl_policy, | ||
653 | .flags = GENL_ADMIN_PERM, | ||
654 | }, | ||
655 | }; | ||
656 | |||
657 | int wl1251_nl_register(void) | ||
658 | { | ||
659 | int err, i; | ||
660 | |||
661 | err = genl_register_family(&wl1251_nl_family); | ||
662 | if (err) | ||
663 | return err; | ||
664 | |||
665 | for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) { | ||
666 | err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]); | ||
667 | if (err) | ||
668 | goto err_out; | ||
669 | } | ||
670 | return 0; | ||
671 | err_out: | ||
672 | genl_unregister_family(&wl1251_nl_family); | ||
673 | return err; | ||
674 | } | ||
675 | |||
676 | void wl1251_nl_unregister(void) | ||
677 | { | ||
678 | genl_unregister_family(&wl1251_nl_family); | ||
679 | } | ||