treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 500
[sfrench/cifs-2.6.git] / drivers / net / wireless / ti / wlcore / vendor_cmd.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This file is part of wlcore
4  *
5  * Copyright (C) 2014 Texas Instruments. All rights reserved.
6  */
7
8 #include <linux/pm_runtime.h>
9
10 #include <net/mac80211.h>
11 #include <net/netlink.h>
12
13 #include "wlcore.h"
14 #include "debug.h"
15 #include "hw_ops.h"
16 #include "vendor_cmd.h"
17
18 static const
19 struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
20         [WLCORE_VENDOR_ATTR_FREQ]               = { .type = NLA_U32 },
21         [WLCORE_VENDOR_ATTR_GROUP_ID]           = { .type = NLA_U32 },
22         [WLCORE_VENDOR_ATTR_GROUP_KEY]          = { .type = NLA_BINARY,
23                                                     .len = WLAN_MAX_KEY_LEN },
24 };
25
26 static int
27 wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy,
28                                      struct wireless_dev *wdev,
29                                      const void *data, int data_len)
30 {
31         struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
32         struct wl1271 *wl = hw->priv;
33         struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
34         int ret;
35
36         wl1271_debug(DEBUG_CMD, "vendor cmd smart config start");
37
38         if (!data)
39                 return -EINVAL;
40
41         ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
42                                    wlcore_vendor_attr_policy, NULL);
43         if (ret)
44                 return ret;
45
46         if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID])
47                 return -EINVAL;
48
49         mutex_lock(&wl->mutex);
50
51         if (unlikely(wl->state != WLCORE_STATE_ON)) {
52                 ret = -EINVAL;
53                 goto out;
54         }
55
56         ret = pm_runtime_get_sync(wl->dev);
57         if (ret < 0) {
58                 pm_runtime_put_noidle(wl->dev);
59                 goto out;
60         }
61
62         ret = wlcore_smart_config_start(wl,
63                         nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]));
64
65         pm_runtime_mark_last_busy(wl->dev);
66         pm_runtime_put_autosuspend(wl->dev);
67 out:
68         mutex_unlock(&wl->mutex);
69
70         return ret;
71 }
72
73 static int
74 wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy,
75                                     struct wireless_dev *wdev,
76                                     const void *data, int data_len)
77 {
78         struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
79         struct wl1271 *wl = hw->priv;
80         int ret;
81
82         wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop");
83
84         mutex_lock(&wl->mutex);
85
86         if (unlikely(wl->state != WLCORE_STATE_ON)) {
87                 ret = -EINVAL;
88                 goto out;
89         }
90
91         ret = pm_runtime_get_sync(wl->dev);
92         if (ret < 0) {
93                 pm_runtime_put_noidle(wl->dev);
94                 goto out;
95         }
96
97         ret = wlcore_smart_config_stop(wl);
98
99         pm_runtime_mark_last_busy(wl->dev);
100         pm_runtime_put_autosuspend(wl->dev);
101 out:
102         mutex_unlock(&wl->mutex);
103
104         return ret;
105 }
106
107 static int
108 wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,
109                                              struct wireless_dev *wdev,
110                                              const void *data, int data_len)
111 {
112         struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
113         struct wl1271 *wl = hw->priv;
114         struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
115         int ret;
116
117         wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key");
118
119         if (!data)
120                 return -EINVAL;
121
122         ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
123                                    wlcore_vendor_attr_policy, NULL);
124         if (ret)
125                 return ret;
126
127         if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] ||
128             !tb[WLCORE_VENDOR_ATTR_GROUP_KEY])
129                 return -EINVAL;
130
131         mutex_lock(&wl->mutex);
132
133         if (unlikely(wl->state != WLCORE_STATE_ON)) {
134                 ret = -EINVAL;
135                 goto out;
136         }
137
138         ret = pm_runtime_get_sync(wl->dev);
139         if (ret < 0) {
140                 pm_runtime_put_noidle(wl->dev);
141                 goto out;
142         }
143
144         ret = wlcore_smart_config_set_group_key(wl,
145                         nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]),
146                         nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]),
147                         nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]));
148
149         pm_runtime_mark_last_busy(wl->dev);
150         pm_runtime_put_autosuspend(wl->dev);
151 out:
152         mutex_unlock(&wl->mutex);
153
154         return ret;
155 }
156
157 static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
158         {
159                 .info = {
160                         .vendor_id = TI_OUI,
161                         .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START,
162                 },
163                 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
164                          WIPHY_VENDOR_CMD_NEED_RUNNING,
165                 .doit = wlcore_vendor_cmd_smart_config_start,
166         },
167         {
168                 .info = {
169                         .vendor_id = TI_OUI,
170                         .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
171                 },
172                 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
173                          WIPHY_VENDOR_CMD_NEED_RUNNING,
174                 .doit = wlcore_vendor_cmd_smart_config_stop,
175         },
176         {
177                 .info = {
178                         .vendor_id = TI_OUI,
179                         .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
180                 },
181                 .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
182                          WIPHY_VENDOR_CMD_NEED_RUNNING,
183                 .doit = wlcore_vendor_cmd_smart_config_set_group_key,
184         },
185 };
186
187 static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = {
188         {
189                 .vendor_id = TI_OUI,
190                 .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC,
191         },
192         {
193                 .vendor_id = TI_OUI,
194                 .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE,
195         },
196 };
197
198 void wlcore_set_vendor_commands(struct wiphy *wiphy)
199 {
200         wiphy->vendor_commands = wlcore_vendor_commands;
201         wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands);
202         wiphy->vendor_events = wlcore_vendor_events;
203         wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events);
204 }