diff options
-rw-r--r-- | drivers/net/wireless/wl12xx/Makefile | 7 | ||||
-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.c | 679 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_netlink.h | 30 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_ops.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_ops.h | 2 | ||||
-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.c | 4 |
25 files changed, 758 insertions, 48 deletions
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index f94970c1d80..d5595a841f5 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 328f88a6756..cecc1fade3d 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 92e724875ad..203f11fd6c2 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 a6a26497dc1..c52a2085671 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 4fa73132baa..4fa73132baa 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 cad258de9b3..d0c2df6b519 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 a2eae54a241..a2eae54a241 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 94ad9948565..a63bc78bfbc 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 562cdcbcc87..562cdcbcc87 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 99529ca89a7..50b5e43d8f3 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 1f4c2f7438a..1f4c2f7438a 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 2a573a6010b..0929461a6d3 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 c8b6cd0b7c3..c8b6cd0b7c3 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 dd75d3d2efa..16cd46c7164 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 00000000000..1bc049fa2ba --- /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 00000000000..acfbd0241b8 --- /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 126537f784b..cdfd2c21899 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 74acf8e3df9..7a78cc9e699 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 f28f194ca6f..83baaa2eb19 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 ad61b4a0b5e..db9f7ed9dd1 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 7ac26ef209b..d73e014d611 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 8a23fdea501..8a23fdea501 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 9c9943f9867..d7eee8ce7ef 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 e48a552b2ea..82b009c3e9e 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 10023fce103..c57330e36df 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) { |