--- /dev/null
+/*
+ * This file is part of wlcore
+ *
+ * Copyright (C) 2014 Texas Instruments. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <net/mac80211.h>
+#include <net/netlink.h>
+
+#include "wlcore.h"
+#include "debug.h"
+#include "ps.h"
+#include "hw_ops.h"
+#include "vendor_cmd.h"
+
+static const
+struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
+ [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
+ [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 },
+ [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32,
+ .len = WLAN_MAX_KEY_LEN },
+};
+
+static int
+wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
+ struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "vendor cmd smart config start");
+
+ if (!data)
+ return -EINVAL;
+
+ ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
+ wlcore_vendor_attr_policy);
+ if (ret)
+ return ret;
+
+ if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID])
+ return -EINVAL;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_smart_config_start(wl,
+ nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]));
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+static int
+wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_smart_config_stop(wl);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static int
+wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
+ struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key");
+
+ if (!data)
+ return -EINVAL;
+
+ ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
+ wlcore_vendor_attr_policy);
+ if (ret)
+ return ret;
+
+ if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] ||
+ !tb[WLCORE_VENDOR_ATTR_GROUP_KEY])
+ return -EINVAL;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_smart_config_set_group_key(wl,
+ nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]),
+ nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]),
+ nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]));
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
+ {
+ .info = {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlcore_vendor_cmd_smart_config_start,
+ },
+ {
+ .info = {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlcore_vendor_cmd_smart_config_stop,
+ },
+ {
+ .info = {
+ .vendor_id = TI_OUI,
+ .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlcore_vendor_cmd_smart_config_set_group_key,
+ },
+};
+
+void wlcore_set_vendor_commands(struct wiphy *wiphy)
+{
+ wiphy->vendor_commands = wlcore_vendor_commands;
+ wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands);
+}
--- /dev/null
+/*
+ * This file is part of wlcore
+ *
+ * Copyright (C) 2014 Texas Instruments. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __WLCORE_VENDOR_H__
+#define __WLCORE_VENDOR_H__
+
+#define TI_OUI 0x080028
+
+enum wlcore_vendor_commands {
+ WLCORE_VENDOR_CMD_SMART_CONFIG_START,
+ WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
+ WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
+
+ NUM_WLCORE_VENDOR_CMD,
+ MAX_WLCORE_VENDOR_CMD = NUM_WLCORE_VENDOR_CMD - 1
+};
+
+enum wlcore_vendor_attributes {
+ WLCORE_VENDOR_ATTR_FREQ,
+ WLCORE_VENDOR_ATTR_PSK,
+ WLCORE_VENDOR_ATTR_SSID,
+ WLCORE_VENDOR_ATTR_GROUP_ID,
+ WLCORE_VENDOR_ATTR_GROUP_KEY,
+
+ NUM_WLCORE_VENDOR_ATTR,
+ MAX_WLCORE_VENDOR_ATTR = NUM_WLCORE_VENDOR_ATTR - 1
+};
+
+#endif /* __WLCORE_VENDOR_H__ */