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