ath5k: fix values for bus error bits in ISR2
[linux-2.6-block.git] / drivers / net / wireless / wl12xx / wl1251_netlink.c
CommitLineData
ef2f8d45 1/*
80301cdc 2 * This file is part of wl1251
ef2f8d45
KV
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
13674118 33#include "wl1251.h"
ef2f8d45
KV
34#include "wl1251_spi.h"
35#include "wl1251_acx.h"
36
37/* FIXME: this should be changed as soon as user space catches up */
80301cdc
KV
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
44enum 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
ef2f8d45 56};
80301cdc
KV
57#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1)
58
59enum 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
ef2f8d45 75};
80301cdc 76#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1)
ef2f8d45 77
80301cdc 78static struct genl_family wl1251_nl_family = {
ef2f8d45 79 .id = GENL_ID_GENERATE,
80301cdc 80 .name = WL1251_NL_NAME,
ef2f8d45 81 .hdrsize = 0,
80301cdc
KV
82 .version = WL1251_NL_VERSION,
83 .maxattr = WL1251_NL_ATTR_MAX,
ef2f8d45
KV
84};
85
86static struct net_device *ifname_to_netdev(struct net *net,
87 struct genl_info *info)
88{
89 char *ifname;
90
80301cdc 91 if (!info->attrs[WL1251_NL_ATTR_IFNAME])
ef2f8d45
KV
92 return NULL;
93
80301cdc 94 ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]);
ef2f8d45 95
80301cdc 96 wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname);
ef2f8d45
KV
97
98 return dev_get_by_name(net, ifname);
99}
100
80301cdc 101static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info)
ef2f8d45
KV
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) {
80301cdc 110 wl1251_error("Wrong interface");
ef2f8d45
KV
111 return NULL;
112 }
113
114 wdev = netdev->ieee80211_ptr;
115 if (wdev == NULL) {
80301cdc 116 wl1251_error("ieee80211_ptr is NULL");
ef2f8d45
KV
117 return NULL;
118 }
119
120 wiphy = wdev->wiphy;
121 if (wiphy == NULL) {
80301cdc 122 wl1251_error("wiphy is NULL");
ef2f8d45
KV
123 return NULL;
124 }
125
126 hw = wiphy_priv(wiphy);
127 if (hw == NULL) {
80301cdc 128 wl1251_error("hw is NULL");
ef2f8d45
KV
129 return NULL;
130 }
131
132 dev_put(netdev);
133
134 return hw->priv;
135}
136
80301cdc 137static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 138{
80301cdc
KV
139 struct wl1251 *wl;
140 struct wl1251_command *cmd;
ef2f8d45
KV
141 char *buf;
142 int buf_len, ret, cmd_len;
143 u8 answer;
144
80301cdc 145 if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM])
ef2f8d45
KV
146 return -EINVAL;
147
80301cdc 148 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 149 if (wl == NULL) {
80301cdc 150 wl1251_error("wl1251 not found");
ef2f8d45
KV
151 return -EINVAL;
152 }
153
154 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
155 if (!cmd)
156 return -ENOMEM;
157
80301cdc
KV
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]);
ef2f8d45
KV
161
162 cmd->header.id = CMD_TEST;
163 memcpy(cmd->parameters, buf, buf_len);
80301cdc 164 cmd_len = sizeof(struct wl1251_cmd_header) + buf_len;
ef2f8d45
KV
165
166 mutex_lock(&wl->mutex);
80301cdc 167 ret = wl1251_cmd_test(wl, cmd, cmd_len, answer);
ef2f8d45
KV
168 mutex_unlock(&wl->mutex);
169
170 if (ret < 0) {
80301cdc 171 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
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,
80301cdc 186 &wl1251_nl_family, 0, WL1251_NL_CMD_TEST);
ef2f8d45
KV
187 if (IS_ERR(hdr)) {
188 ret = PTR_ERR(hdr);
189 goto nla_put_failure;
190 }
191
80301cdc
KV
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,
ef2f8d45
KV
195 sizeof(*cmd), cmd);
196
197 ret = genlmsg_end(msg, hdr);
198 if (ret < 0) {
80301cdc 199 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
200 goto nla_put_failure;
201 }
202
80301cdc 203 wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
ef2f8d45
KV
204 ret = genlmsg_reply(msg, info);
205 goto out;
206
207 nla_put_failure:
208 nlmsg_free(msg);
209 } else
80301cdc 210 wl1251_debug(DEBUG_NETLINK, "TEST cmd sent");
ef2f8d45
KV
211
212out:
213 kfree(cmd);
214 return ret;
215}
216
80301cdc 217static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 218{
80301cdc 219 struct wl1251 *wl;
ef2f8d45
KV
220 struct sk_buff *msg;
221 int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
80301cdc 222 struct wl1251_command *cmd;
ef2f8d45
KV
223 void *hdr;
224
80301cdc 225 if (!info->attrs[WL1251_NL_ATTR_CMD_IE])
ef2f8d45
KV
226 return -EINVAL;
227
80301cdc 228 if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
ef2f8d45
KV
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
80301cdc 239 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 240 if (wl == NULL) {
80301cdc 241 wl1251_error("wl1251 not found");
ef2f8d45
KV
242 ret = -EINVAL;
243 goto nla_put_failure;
244 }
245
246 /* acx id */
80301cdc 247 cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]);
ef2f8d45
KV
248
249 /* maximum length of acx, including all headers */
80301cdc 250 cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
ef2f8d45 251
80301cdc 252 wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
ef2f8d45
KV
253 cmd_ie, cmd_ie_len);
254
255 mutex_lock(&wl->mutex);
80301cdc 256 ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
ef2f8d45
KV
257 mutex_unlock(&wl->mutex);
258
259 if (ret < 0) {
80301cdc 260 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
261 goto nla_put_failure;
262 }
263
264 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
80301cdc 265 &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE);
ef2f8d45
KV
266 if (IS_ERR(hdr)) {
267 ret = PTR_ERR(hdr);
268 goto nla_put_failure;
269 }
270
80301cdc
KV
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);
ef2f8d45
KV
274
275 ret = genlmsg_end(msg, hdr);
276 if (ret < 0) {
80301cdc 277 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
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
80301cdc 291static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info)
ef2f8d45
KV
292{
293 int ret = 0, cmd_ie_len, acx_len;
294 struct acx_header *acx = NULL;
295 struct sk_buff *msg;
80301cdc 296 struct wl1251 *wl;
ef2f8d45
KV
297 void *cmd_ie;
298 u16 *id;
299
80301cdc 300 if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER])
ef2f8d45
KV
301 return -EINVAL;
302
80301cdc 303 if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
ef2f8d45
KV
304 return -EINVAL;
305
306 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
307 if (!msg)
308 return -ENOMEM;
309
80301cdc 310 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 311 if (wl == NULL) {
80301cdc 312 wl1251_error("wl1251 not found");
ef2f8d45
KV
313 ret = -EINVAL;
314 goto nla_put_failure;
315 }
316
317 /* contains the acx header but not the cmd header */
80301cdc 318 cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]);
ef2f8d45 319
80301cdc 320 cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
ef2f8d45
KV
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);
80301cdc 337 ret = wl1251_cmd_configure(wl, *id, acx, acx_len);
ef2f8d45
KV
338 mutex_unlock(&wl->mutex);
339
340 if (ret < 0) {
80301cdc 341 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
342 goto nla_put_failure;
343 }
344
80301cdc 345 wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
ef2f8d45
KV
346
347 nla_put_failure:
348 kfree(acx);
349 nlmsg_free(msg);
350
351 return ret;
352}
353
80301cdc 354static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 355{
80301cdc 356 struct wl1251 *wl;
ef2f8d45
KV
357 struct sk_buff *msg;
358 u32 reg_addr, *reg_value = NULL;
359 int ret = 0;
360 void *hdr;
361
80301cdc 362 if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
ef2f8d45
KV
363 return -EINVAL;
364
365 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
366 if (!msg)
367 return -ENOMEM;
368
80301cdc 369 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 370 if (wl == NULL) {
80301cdc 371 wl1251_error("wl1251 not found");
ef2f8d45
KV
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
80301cdc 382 reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
ef2f8d45 383
80301cdc 384 wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
ef2f8d45
KV
385
386 mutex_lock(&wl->mutex);
80301cdc 387 ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value,
ef2f8d45
KV
388 sizeof(*reg_value));
389 mutex_unlock(&wl->mutex);
390
391 if (ret < 0) {
80301cdc 392 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
393 goto nla_put_failure;
394 }
395
396
397 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
80301cdc 398 &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
ef2f8d45
KV
399 if (IS_ERR(hdr)) {
400 ret = PTR_ERR(hdr);
401 goto nla_put_failure;
402 }
403
80301cdc
KV
404 NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
405 nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
ef2f8d45 406
80301cdc 407 NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value);
ef2f8d45
KV
408
409 ret = genlmsg_end(msg, hdr);
410 if (ret < 0) {
80301cdc 411 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
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
80301cdc 426static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 427{
80301cdc 428 struct wl1251 *wl;
ef2f8d45
KV
429 int ret = 0;
430
80301cdc 431 if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER])
ef2f8d45
KV
432 return -EINVAL;
433
80301cdc 434 if (!info->attrs[WL1251_NL_ATTR_NVS_LEN])
ef2f8d45
KV
435 return -EINVAL;
436
80301cdc 437 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 438 if (wl == NULL) {
80301cdc 439 wl1251_error("wl1251 not found");
ef2f8d45
KV
440 return -EINVAL;
441 }
442
443 mutex_lock(&wl->mutex);
80301cdc 444 wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]);
ef2f8d45 445 if (wl->nvs_len % 4) {
80301cdc 446 wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len);
ef2f8d45
KV
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) {
80301cdc 456 wl1251_error("Can't allocate NVS");
ef2f8d45
KV
457 ret = -ENOMEM;
458 goto out;
459 }
460
461 memcpy(wl->nvs,
80301cdc 462 nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]),
ef2f8d45
KV
463 wl->nvs_len);
464
80301cdc 465 wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
ef2f8d45
KV
466 wl->nvs_len);
467
468out:
469 mutex_unlock(&wl->mutex);
470
471 return ret;
472}
473
80301cdc 474static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 475{
80301cdc 476 struct wl1251 *wl;
ef2f8d45
KV
477 u32 addr, val;
478 int ret = 0;
479 struct sk_buff *msg;
480 void *hdr;
481
80301cdc 482 if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
ef2f8d45
KV
483 return -EINVAL;
484
485 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
486 if (!msg)
487 return -ENOMEM;
488
80301cdc 489 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 490 if (wl == NULL) {
80301cdc 491 wl1251_error("wl1251 not found");
ef2f8d45
KV
492 return -EINVAL;
493 }
494
80301cdc 495 addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
ef2f8d45
KV
496
497 mutex_lock(&wl->mutex);
80301cdc 498 val = wl1251_reg_read32(wl, addr);
ef2f8d45
KV
499 mutex_unlock(&wl->mutex);
500
501 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
80301cdc 502 &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
ef2f8d45
KV
503 if (IS_ERR(hdr)) {
504 ret = PTR_ERR(hdr);
505 goto nla_put_failure;
506 }
507
80301cdc
KV
508 NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
509 nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
ef2f8d45 510
80301cdc 511 NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val);
ef2f8d45
KV
512
513 ret = genlmsg_end(msg, hdr);
514 if (ret < 0) {
80301cdc 515 wl1251_error("%s() failed", __func__);
ef2f8d45
KV
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
80301cdc 527static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 528{
80301cdc 529 struct wl1251 *wl;
ef2f8d45
KV
530 u32 addr, val;
531
80301cdc 532 if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
ef2f8d45
KV
533 return -EINVAL;
534
80301cdc 535 if (!info->attrs[WL1251_NL_ATTR_REG_VAL])
ef2f8d45
KV
536 return -EINVAL;
537
80301cdc 538 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 539 if (wl == NULL) {
80301cdc 540 wl1251_error("wl1251 not found");
ef2f8d45
KV
541 return -EINVAL;
542 }
543
80301cdc
KV
544 addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
545 val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]);
ef2f8d45
KV
546
547 mutex_lock(&wl->mutex);
80301cdc 548 wl1251_reg_write32(wl, addr, val);
ef2f8d45
KV
549 mutex_unlock(&wl->mutex);
550
551 return 0;
552}
553
80301cdc 554static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
ef2f8d45 555{
80301cdc 556 struct wl1251 *wl;
ef2f8d45
KV
557 u32 val;
558 int ret;
559
80301cdc 560 if (!info->attrs[WL1251_NL_ATTR_PLT_MODE])
ef2f8d45
KV
561 return -EINVAL;
562
80301cdc 563 wl = ifname_to_wl1251(&init_net, info);
ef2f8d45 564 if (wl == NULL) {
80301cdc 565 wl1251_error("wl1251 not found");
ef2f8d45
KV
566 return -EINVAL;
567 }
568
80301cdc 569 val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]);
ef2f8d45
KV
570
571 switch (val) {
572 case 0:
80301cdc 573 ret = wl1251_plt_stop(wl);
ef2f8d45
KV
574 break;
575 case 1:
80301cdc 576 ret = wl1251_plt_start(wl);
ef2f8d45
KV
577 break;
578 default:
579 ret = -EINVAL;
580 break;
581 }
582
583 return ret;
584}
585
80301cdc
KV
586static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = {
587 [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
ef2f8d45 588 .len = IFNAMSIZ-1 },
80301cdc
KV
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 },
ef2f8d45
KV
604};
605
80301cdc 606static struct genl_ops wl1251_nl_ops[] = {
ef2f8d45 607 {
80301cdc
KV
608 .cmd = WL1251_NL_CMD_TEST,
609 .doit = wl1251_nl_test_cmd,
610 .policy = wl1251_nl_policy,
ef2f8d45
KV
611 .flags = GENL_ADMIN_PERM,
612 },
613 {
80301cdc
KV
614 .cmd = WL1251_NL_CMD_INTERROGATE,
615 .doit = wl1251_nl_interrogate,
616 .policy = wl1251_nl_policy,
ef2f8d45
KV
617 .flags = GENL_ADMIN_PERM,
618 },
619 {
80301cdc
KV
620 .cmd = WL1251_NL_CMD_CONFIGURE,
621 .doit = wl1251_nl_configure,
622 .policy = wl1251_nl_policy,
ef2f8d45
KV
623 .flags = GENL_ADMIN_PERM,
624 },
625 {
80301cdc
KV
626 .cmd = WL1251_NL_CMD_PHY_REG_READ,
627 .doit = wl1251_nl_phy_reg_read,
628 .policy = wl1251_nl_policy,
ef2f8d45
KV
629 .flags = GENL_ADMIN_PERM,
630 },
631 {
80301cdc
KV
632 .cmd = WL1251_NL_CMD_NVS_PUSH,
633 .doit = wl1251_nl_nvs_push,
634 .policy = wl1251_nl_policy,
ef2f8d45
KV
635 .flags = GENL_ADMIN_PERM,
636 },
637 {
80301cdc
KV
638 .cmd = WL1251_NL_CMD_REG_WRITE,
639 .doit = wl1251_nl_reg_write,
640 .policy = wl1251_nl_policy,
ef2f8d45
KV
641 .flags = GENL_ADMIN_PERM,
642 },
643 {
80301cdc
KV
644 .cmd = WL1251_NL_CMD_REG_READ,
645 .doit = wl1251_nl_reg_read,
646 .policy = wl1251_nl_policy,
ef2f8d45
KV
647 .flags = GENL_ADMIN_PERM,
648 },
649 {
80301cdc
KV
650 .cmd = WL1251_NL_CMD_SET_PLT_MODE,
651 .doit = wl1251_nl_set_plt_mode,
652 .policy = wl1251_nl_policy,
ef2f8d45
KV
653 .flags = GENL_ADMIN_PERM,
654 },
655};
656
80301cdc 657int wl1251_nl_register(void)
ef2f8d45
KV
658{
659 int err, i;
660
80301cdc 661 err = genl_register_family(&wl1251_nl_family);
ef2f8d45
KV
662 if (err)
663 return err;
664
80301cdc
KV
665 for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) {
666 err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]);
ef2f8d45
KV
667 if (err)
668 goto err_out;
669 }
670 return 0;
671 err_out:
80301cdc 672 genl_unregister_family(&wl1251_nl_family);
ef2f8d45
KV
673 return err;
674}
675
80301cdc 676void wl1251_nl_unregister(void)
ef2f8d45 677{
80301cdc 678 genl_unregister_family(&wl1251_nl_family);
ef2f8d45 679}