summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/wl12xx/Makefile7
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c (renamed from drivers/net/wireless/wl12xx/acx.c)6
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h (renamed from drivers/net/wireless/wl12xx/acx.h)2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c (renamed from drivers/net/wireless/wl12xx/boot.c)6
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.h (renamed from drivers/net/wireless/wl12xx/boot.h)0
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c (renamed from drivers/net/wireless/wl12xx/cmd.c)8
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h (renamed from drivers/net/wireless/wl12xx/cmd.h)0
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c (renamed from drivers/net/wireless/wl12xx/debugfs.c)6
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.h (renamed from drivers/net/wireless/wl12xx/debugfs.h)0
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.c (renamed from drivers/net/wireless/wl12xx/event.c)6
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h (renamed from drivers/net/wireless/wl12xx/event.h)0
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c (renamed from drivers/net/wireless/wl12xx/init.c)6
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h (renamed from drivers/net/wireless/wl12xx/init.h)0
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c (renamed from drivers/net/wireless/wl12xx/main.c)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.c679
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.c14
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c (renamed from drivers/net/wireless/wl12xx/ps.c)4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.h (renamed from drivers/net/wireless/wl12xx/ps.h)2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c (renamed from drivers/net/wireless/wl12xx/rx.c)5
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h (renamed from drivers/net/wireless/wl12xx/rx.h)0
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c (renamed from drivers/net/wireless/wl12xx/spi.c)3
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.h (renamed from drivers/net/wireless/wl12xx/spi.h)4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c4
25 files changed, 758 insertions, 48 deletions
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index f94970c1d80d..d5595a841f5f 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,5 @@
-wl1251-objs = main.o spi.o event.o wl1251_tx.o rx.o \
- ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \
- debugfs.o
+wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \
+ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
+ wl1251_acx.o wl1251_boot.o wl1251_init.o \
+ wl1251_ops.o wl1251_debugfs.o
obj-$(CONFIG_WL1251) += wl1251.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
index 328f88a67563..cecc1fade3dc 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.c
@@ -1,4 +1,4 @@
-#include "acx.h"
+#include "wl1251_acx.h"
#include <linux/module.h>
#include <linux/crc7.h>
@@ -7,8 +7,8 @@
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
u8 mgt_rate, u8 mgt_mod)
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index 92e724875ade..203f11fd6c25 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -26,7 +26,7 @@
#define __WL12XX_ACX_H__
#include "wl12xx.h"
-#include "cmd.h"
+#include "wl1251_cmd.h"
/* Target's information element */
struct acx_header {
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index a6a26497dc13..c52a2085671b 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -24,9 +24,9 @@
#include <linux/gpio.h>
#include "reg.h"
-#include "boot.h"
-#include "spi.h"
-#include "event.h"
+#include "wl1251_boot.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
{
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h
index 4fa73132baae..4fa73132baae 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.h
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
index cad258de9b33..d0c2df6b5193 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c
@@ -1,4 +1,4 @@
-#include "cmd.h"
+#include "wl1251_cmd.h"
#include <linux/module.h>
#include <linux/crc7.h>
@@ -7,9 +7,9 @@
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-#include "acx.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_acx.h"
/**
* send command to firmware
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index a2eae54a241c..a2eae54a241c 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
index 94ad99485651..a63bc78bfbc2 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
@@ -21,13 +21,13 @@
*
*/
-#include "debugfs.h"
+#include "wl1251_debugfs.h"
#include <linux/skbuff.h>
#include "wl12xx.h"
-#include "acx.h"
-#include "ps.h"
+#include "wl1251_acx.h"
+#include "wl1251_ps.h"
/* ms */
#define WL12XX_DEBUGFS_STATS_LIFETIME 1000
diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
index 562cdcbcc874..562cdcbcc874 100644
--- a/drivers/net/wireless/wl12xx/debugfs.h
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/wl1251_event.c
index 99529ca89a7e..50b5e43d8f39 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/wl1251_event.c
@@ -24,9 +24,9 @@
#include "wl12xx.h"
#include "reg.h"
-#include "spi.h"
-#include "event.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_ps.h"
static int wl12xx_event_scan_complete(struct wl12xx *wl,
struct event_mailbox *mbox)
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index 1f4c2f7438a7..1f4c2f7438a7 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/wl1251_init.c
index 2a573a6010bd..0929461a6d3c 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/wl1251_init.c
@@ -24,10 +24,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "init.h"
+#include "wl1251_init.h"
#include "wl12xx_80211.h"
-#include "acx.h"
-#include "cmd.h"
+#include "wl1251_acx.h"
+#include "wl1251_cmd.h"
int wl12xx_hw_init_hwenc_config(struct wl12xx *wl)
{
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/wl1251_init.h
index c8b6cd0b7c3e..c8b6cd0b7c3e 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/wl1251_init.h
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index dd75d3d2efa6..16cd46c7164b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -35,13 +35,13 @@
#include "wl12xx_80211.h"
#include "reg.h"
#include "wl1251_ops.h"
-#include "spi.h"
-#include "event.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
#include "wl1251_tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-#include "debugfs.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+#include "wl1251_debugfs.h"
static void wl12xx_disable_interrupts(struct wl12xx *wl)
{
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c
new file mode 100644
index 000000000000..1bc049fa2bae
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c
@@ -0,0 +1,679 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include "wl1251_netlink.h"
+
+#include <linux/mutex.h>
+#include <linux/socket.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/genetlink.h>
+#include <net/wireless.h>
+#include <net/mac80211.h>
+
+#include "wl12xx.h"
+#include "wl1251_spi.h"
+#include "wl1251_acx.h"
+
+/* FIXME: this should be changed as soon as user space catches up */
+#define WL12XX_NL_NAME "wl1251"
+#define WL12XX_NL_VERSION 1
+
+#define WL12XX_MAX_TEST_LENGTH 1024
+#define WL12XX_MAX_NVS_LENGTH 1024
+
+enum wl12xx_nl_commands {
+ WL12XX_NL_CMD_UNSPEC,
+ WL12XX_NL_CMD_TEST,
+ WL12XX_NL_CMD_INTERROGATE,
+ WL12XX_NL_CMD_CONFIGURE,
+ WL12XX_NL_CMD_PHY_REG_READ,
+ WL12XX_NL_CMD_NVS_PUSH,
+ WL12XX_NL_CMD_REG_WRITE,
+ WL12XX_NL_CMD_REG_READ,
+ WL12XX_NL_CMD_SET_PLT_MODE,
+
+ __WL12XX_NL_CMD_AFTER_LAST
+};
+#define WL12XX_NL_CMD_MAX (__WL12XX_NL_CMD_AFTER_LAST - 1)
+
+enum wl12xx_nl_attrs {
+ WL12XX_NL_ATTR_UNSPEC,
+ WL12XX_NL_ATTR_IFNAME,
+ WL12XX_NL_ATTR_CMD_TEST_PARAM,
+ WL12XX_NL_ATTR_CMD_TEST_ANSWER,
+ WL12XX_NL_ATTR_CMD_IE,
+ WL12XX_NL_ATTR_CMD_IE_LEN,
+ WL12XX_NL_ATTR_CMD_IE_BUFFER,
+ WL12XX_NL_ATTR_CMD_IE_ANSWER,
+ WL12XX_NL_ATTR_REG_ADDR,
+ WL12XX_NL_ATTR_REG_VAL,
+ WL12XX_NL_ATTR_NVS_BUFFER,
+ WL12XX_NL_ATTR_NVS_LEN,
+ WL12XX_NL_ATTR_PLT_MODE,
+
+ __WL12XX_NL_ATTR_AFTER_LAST
+};
+#define WL12XX_NL_ATTR_MAX (__WL12XX_NL_ATTR_AFTER_LAST - 1)
+
+static struct genl_family wl12xx_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = WL12XX_NL_NAME,
+ .hdrsize = 0,
+ .version = WL12XX_NL_VERSION,
+ .maxattr = WL12XX_NL_ATTR_MAX,
+};
+
+static struct net_device *ifname_to_netdev(struct net *net,
+ struct genl_info *info)
+{
+ char *ifname;
+
+ if (!info->attrs[WL12XX_NL_ATTR_IFNAME])
+ return NULL;
+
+ ifname = nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]);
+
+ wl12xx_debug(DEBUG_NETLINK, "Looking for %s", ifname);
+
+ return dev_get_by_name(net, ifname);
+}
+
+static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info)
+{
+ struct net_device *netdev;
+ struct wireless_dev *wdev;
+ struct wiphy *wiphy;
+ struct ieee80211_hw *hw;
+
+ netdev = ifname_to_netdev(net, info);
+ if (netdev == NULL) {
+ wl12xx_error("Wrong interface");
+ return NULL;
+ }
+
+ wdev = netdev->ieee80211_ptr;
+ if (wdev == NULL) {
+ wl12xx_error("ieee80211_ptr is NULL");
+ return NULL;
+ }
+
+ wiphy = wdev->wiphy;
+ if (wiphy == NULL) {
+ wl12xx_error("wiphy is NULL");
+ return NULL;
+ }
+
+ hw = wiphy_priv(wiphy);
+ if (hw == NULL) {
+ wl12xx_error("hw is NULL");
+ return NULL;
+ }
+
+ dev_put(netdev);
+
+ return hw->priv;
+}
+
+static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ struct wl12xx_command *cmd;
+ char *buf;
+ int buf_len, ret, cmd_len;
+ u8 answer;
+
+ if (!info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM])
+ return -EINVAL;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ buf = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]);
+ buf_len = nla_len(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]);
+ answer = nla_get_u8(info->attrs[WL12XX_NL_ATTR_CMD_TEST_ANSWER]);
+
+ cmd->header.id = CMD_TEST;
+ memcpy(cmd->parameters, buf, buf_len);
+ cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len;
+
+ mutex_lock(&wl->mutex);
+ ret = wl12xx_cmd_test(wl, cmd, cmd_len, answer);
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto out;
+ }
+
+ if (answer) {
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+ &wl12xx_nl_family, 0, WL12XX_NL_CMD_TEST);
+ if (IS_ERR(hdr)) {
+ ret = PTR_ERR(hdr);
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
+ nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
+ NLA_PUT(msg, WL12XX_NL_ATTR_CMD_TEST_ANSWER,
+ sizeof(*cmd), cmd);
+
+ ret = genlmsg_end(msg, hdr);
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+ wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
+ ret = genlmsg_reply(msg, info);
+ goto out;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+ } else
+ wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent");
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ struct sk_buff *msg;
+ int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
+ struct wl12xx_command *cmd;
+ void *hdr;
+
+ if (!info->attrs[WL12XX_NL_ATTR_CMD_IE])
+ return -EINVAL;
+
+ if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN])
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ ret = -EINVAL;
+ goto nla_put_failure;
+ }
+
+ /* acx id */
+ cmd_ie = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE]);
+
+ /* maximum length of acx, including all headers */
+ cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]);
+
+ wl12xx_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
+ cmd_ie, cmd_ie_len);
+
+ mutex_lock(&wl->mutex);
+ ret = wl12xx_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+ &wl12xx_nl_family, 0, WL12XX_NL_CMD_INTERROGATE);
+ if (IS_ERR(hdr)) {
+ ret = PTR_ERR(hdr);
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
+ nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
+ NLA_PUT(msg, WL12XX_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd);
+
+ ret = genlmsg_end(msg, hdr);
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+ kfree(cmd);
+ return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+ kfree(cmd);
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info)
+{
+ int ret = 0, cmd_ie_len, acx_len;
+ struct acx_header *acx = NULL;
+ struct sk_buff *msg;
+ struct wl12xx *wl;
+ void *cmd_ie;
+ u16 *id;
+
+ if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER])
+ return -EINVAL;
+
+ if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN])
+ return -EINVAL;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ ret = -EINVAL;
+ goto nla_put_failure;
+ }
+
+ /* contains the acx header but not the cmd header */
+ cmd_ie = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]);
+
+ cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]);
+
+ /* acx id is in the first two bytes */
+ id = cmd_ie;
+
+ /* need to add acx_header before cmd_ie, so create a new command */
+ acx_len = sizeof(struct acx_header) + cmd_ie_len;
+ acx = kzalloc(acx_len, GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto nla_put_failure;
+ }
+
+ /* copy the acx header and the payload */
+ memcpy(&acx->id, cmd_ie, cmd_ie_len);
+
+ mutex_lock(&wl->mutex);
+ ret = wl12xx_cmd_configure(wl, *id, acx, acx_len);
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+ wl12xx_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
+
+ nla_put_failure:
+ kfree(acx);
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ struct sk_buff *msg;
+ u32 reg_addr, *reg_value = NULL;
+ int ret = 0;
+ void *hdr;
+
+ if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR])
+ return -EINVAL;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ ret = -EINVAL;
+ goto nla_put_failure;
+ }
+
+ reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL);
+ if (!reg_value) {
+ ret = -ENOMEM;
+ goto nla_put_failure;
+ }
+
+ reg_addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]);
+
+ wl12xx_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
+
+ mutex_lock(&wl->mutex);
+ ret = wl12xx_cmd_read_memory(wl, reg_addr, reg_value,
+ sizeof(*reg_value));
+ mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+
+ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+ &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ);
+ if (IS_ERR(hdr)) {
+ ret = PTR_ERR(hdr);
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
+ nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
+
+ NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, *reg_value);
+
+ ret = genlmsg_end(msg, hdr);
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+ kfree(reg_value);
+
+ return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+ nlmsg_free(msg);
+ kfree(reg_value);
+
+ return ret;
+}
+
+static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ int ret = 0;
+
+ if (!info->attrs[WL12XX_NL_ATTR_NVS_BUFFER])
+ return -EINVAL;
+
+ if (!info->attrs[WL12XX_NL_ATTR_NVS_LEN])
+ return -EINVAL;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ return -EINVAL;
+ }
+
+ mutex_lock(&wl->mutex);
+ wl->nvs_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_NVS_LEN]);
+ if (wl->nvs_len % 4) {
+ wl12xx_error("NVS size is not multiple of 32: %d", wl->nvs_len);
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ /* If we already have an NVS, we should free it */
+ kfree(wl->nvs);
+
+ wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL);
+ if (wl->nvs == NULL) {
+ wl12xx_error("Can't allocate NVS");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(wl->nvs,
+ nla_data(info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]),
+ wl->nvs_len);
+
+ wl12xx_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
+ wl->nvs_len);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ u32 addr, val;
+ int ret = 0;
+ struct sk_buff *msg;
+ void *hdr;
+
+ if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR])
+ return -EINVAL;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ return -EINVAL;
+ }
+
+ addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]);
+
+ mutex_lock(&wl->mutex);
+ val = wl12xx_reg_read32(wl, addr);
+ mutex_unlock(&wl->mutex);
+
+ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+ &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ);
+ if (IS_ERR(hdr)) {
+ ret = PTR_ERR(hdr);
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME,
+ nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]));
+
+ NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, val);
+
+ ret = genlmsg_end(msg, hdr);
+ if (ret < 0) {
+ wl12xx_error("%s() failed", __func__);
+ goto nla_put_failure;
+ }
+
+ return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+static int wl12xx_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ u32 addr, val;
+
+ if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR])
+ return -EINVAL;
+
+ if (!info->attrs[WL12XX_NL_ATTR_REG_VAL])
+ return -EINVAL;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ return -EINVAL;
+ }
+
+ addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]);
+ val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_VAL]);
+
+ mutex_lock(&wl->mutex);
+ wl12xx_reg_write32(wl, addr, val);
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
+{
+ struct wl12xx *wl;
+ u32 val;
+ int ret;
+
+ if (!info->attrs[WL12XX_NL_ATTR_PLT_MODE])
+ return -EINVAL;
+
+ wl = ifname_to_wl12xx(&init_net, info);
+ if (wl == NULL) {
+ wl12xx_error("wl12xx not found");
+ return -EINVAL;
+ }
+
+ val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_PLT_MODE]);
+
+ switch (val) {
+ case 0:
+ ret = wl12xx_plt_stop(wl);
+ break;
+ case 1:
+ ret = wl12xx_plt_start(wl);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static struct nla_policy wl12xx_nl_policy[WL12XX_NL_ATTR_MAX + 1] = {
+ [WL12XX_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
+ .len = IFNAMSIZ-1 },
+ [WL12XX_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY,
+ .len = WL12XX_MAX_TEST_LENGTH },
+ [WL12XX_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 },
+ [WL12XX_NL_ATTR_CMD_IE] = { .type = NLA_U32 },
+ [WL12XX_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 },
+ [WL12XX_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY,
+ .len = WL12XX_MAX_TEST_LENGTH },
+ [WL12XX_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY,
+ .len = WL12XX_MAX_TEST_LENGTH },
+ [WL12XX_NL_ATTR_REG_ADDR] = { .type = NLA_U32 },
+ [WL12XX_NL_ATTR_REG_VAL] = { .type = NLA_U32 },
+ [WL12XX_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY,
+ .len = WL12XX_MAX_NVS_LENGTH },
+ [WL12XX_NL_ATTR_NVS_LEN] = { .type = NLA_U32 },
+ [WL12XX_NL_ATTR_PLT_MODE] = { .type = NLA_U32 },
+};
+
+static struct genl_ops wl12xx_nl_ops[] = {
+ {
+ .cmd = WL12XX_NL_CMD_TEST,
+ .doit = wl12xx_nl_test_cmd,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_INTERROGATE,
+ .doit = wl12xx_nl_interrogate,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_CONFIGURE,
+ .doit = wl12xx_nl_configure,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_PHY_REG_READ,
+ .doit = wl12xx_nl_phy_reg_read,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_NVS_PUSH,
+ .doit = wl12xx_nl_nvs_push,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_REG_WRITE,
+ .doit = wl12xx_nl_reg_write,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_REG_READ,
+ .doit = wl12xx_nl_reg_read,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = WL12XX_NL_CMD_SET_PLT_MODE,
+ .doit = wl12xx_nl_set_plt_mode,
+ .policy = wl12xx_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+};
+
+int wl12xx_nl_register(void)
+{
+ int err, i;
+
+ err = genl_register_family(&wl12xx_nl_family);
+ if (err)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(wl12xx_nl_ops); i++) {
+ err = genl_register_ops(&wl12xx_nl_family, &wl12xx_nl_ops[i]);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+ err_out:
+ genl_unregister_family(&wl12xx_nl_family);
+ return err;
+}
+
+void wl12xx_nl_unregister(void)
+{
+ genl_unregister_family(&wl12xx_nl_family);
+}
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
new file mode 100644
index 000000000000..acfbd0241b82
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL12XX_NETLINK_H__
+#define __WL12XX_NETLINK_H__
+
+int wl12xx_nl_register(void);
+void wl12xx_nl_unregister(void);
+
+#endif /* __WL12XX_NETLINK_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c
index 126537f784b1..cdfd2c218993 100644
--- a/drivers/net/wireless/wl12xx/wl1251_ops.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.c
@@ -26,14 +26,14 @@
#include "wl1251_ops.h"
#include "reg.h"
-#include "spi.h"
-#include "boot.h"
-#include "event.h"
-#include "acx.h"
+#include "wl1251_spi.h"
+#include "wl1251_boot.h"
+#include "wl1251_event.h"
+#include "wl1251_acx.h"
#include "wl1251_tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h
index 74acf8e3df99..7a78cc9e699f 100644
--- a/drivers/net/wireless/wl12xx/wl1251_ops.h
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.h
@@ -27,7 +27,7 @@
#include <linux/bitops.h>
#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251_acx.h"
#define WL1251_FW_NAME "wl1251-fw.bin"
#define WL1251_NVS_NAME "wl1251-nvs.bin"
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
index f28f194ca6fb..83baaa2eb19d 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -22,8 +22,8 @@
*/
#include "reg.h"
-#include "ps.h"
-#include "spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_spi.h"
#define WL12XX_WAKEUP_TIMEOUT 2000
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h
index ad61b4a0b5ee..db9f7ed9dd1d 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.h
@@ -26,7 +26,7 @@
*/
#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251_acx.h"
int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode);
void wl12xx_ps_elp_sleep(struct wl12xx *wl);
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 7ac26ef209b7..d73e014d6118 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -27,8 +27,9 @@
#include "wl12xx.h"
#include "reg.h"
-#include "spi.h"
-#include "rx.h"
+#include "wl1251_spi.h"
+#include "wl1251_rx.h"
+#include "wl1251_acx.h"
static void wl12xx_rx_header(struct wl12xx *wl,
struct wl12xx_rx_descriptor *desc)
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 8a23fdea5016..8a23fdea5016 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index 9c9943f98674..d7eee8ce7ef2 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -28,8 +28,7 @@
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1251_spi.h"
static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
{
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h
index e48a552b2ea9..82b009c3e9ec 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.h
@@ -25,8 +25,8 @@
#ifndef __WL12XX_SPI_H__
#define __WL12XX_SPI_H__
-#include "cmd.h"
-#include "acx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index 10023fce1031..c57330e36dfb 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -27,9 +27,9 @@
#include "wl12xx.h"
#include "reg.h"
-#include "spi.h"
+#include "wl1251_spi.h"
#include "wl1251_tx.h"
-#include "ps.h"
+#include "wl1251_ps.h"
static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
{