~ubuntu-branches/ubuntu/trusty/linux-backports-modules-3.2.0/trusty

« back to all changes in this revision

Viewing changes to updates/cw-3.3/drivers/net/wireless/wl12xx/testmode.c

  • Committer: Package Import Robot
  • Author(s): Leann Ogasawara
  • Date: 2012-02-15 08:42:08 UTC
  • Revision ID: package-import@ubuntu.com-20120215084208-2gcs2zosufz014pi
Tags: 3.2.0-18.1
* Open Precise LBM
* Add compat-wireless v3.3
* Consolidated amd64 server flavour into generic
* Remove lpia control file
* Update Vcs-Git to ubuntu-preicse-lbm

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of wl1271
 
3
 *
 
4
 * Copyright (C) 2010 Nokia Corporation
 
5
 *
 
6
 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License
 
10
 * version 2 as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
20
 * 02110-1301 USA
 
21
 *
 
22
 */
 
23
#include "testmode.h"
 
24
 
 
25
#include <linux/slab.h>
 
26
#include <net/genetlink.h>
 
27
 
 
28
#include "wl12xx.h"
 
29
#include "debug.h"
 
30
#include "acx.h"
 
31
#include "reg.h"
 
32
#include "ps.h"
 
33
 
 
34
#define WL1271_TM_MAX_DATA_LENGTH 1024
 
35
 
 
36
enum wl1271_tm_commands {
 
37
        WL1271_TM_CMD_UNSPEC,
 
38
        WL1271_TM_CMD_TEST,
 
39
        WL1271_TM_CMD_INTERROGATE,
 
40
        WL1271_TM_CMD_CONFIGURE,
 
41
        WL1271_TM_CMD_NVS_PUSH,         /* Not in use. Keep to not break ABI */
 
42
        WL1271_TM_CMD_SET_PLT_MODE,
 
43
        WL1271_TM_CMD_RECOVER,
 
44
 
 
45
        __WL1271_TM_CMD_AFTER_LAST
 
46
};
 
47
#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
 
48
 
 
49
enum wl1271_tm_attrs {
 
50
        WL1271_TM_ATTR_UNSPEC,
 
51
        WL1271_TM_ATTR_CMD_ID,
 
52
        WL1271_TM_ATTR_ANSWER,
 
53
        WL1271_TM_ATTR_DATA,
 
54
        WL1271_TM_ATTR_IE_ID,
 
55
        WL1271_TM_ATTR_PLT_MODE,
 
56
 
 
57
        __WL1271_TM_ATTR_AFTER_LAST
 
58
};
 
59
#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
 
60
 
 
61
static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
 
62
        [WL1271_TM_ATTR_CMD_ID] =       { .type = NLA_U32 },
 
63
        [WL1271_TM_ATTR_ANSWER] =       { .type = NLA_U8 },
 
64
        [WL1271_TM_ATTR_DATA] =         { .type = NLA_BINARY,
 
65
                                          .len = WL1271_TM_MAX_DATA_LENGTH },
 
66
        [WL1271_TM_ATTR_IE_ID] =        { .type = NLA_U32 },
 
67
        [WL1271_TM_ATTR_PLT_MODE] =     { .type = NLA_U32 },
 
68
};
 
69
 
 
70
 
 
71
static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
 
72
{
 
73
        int buf_len, ret, len;
 
74
        struct sk_buff *skb;
 
75
        void *buf;
 
76
        u8 answer = 0;
 
77
 
 
78
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
 
79
 
 
80
        if (!tb[WL1271_TM_ATTR_DATA])
 
81
                return -EINVAL;
 
82
 
 
83
        buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
 
84
        buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
 
85
 
 
86
        if (tb[WL1271_TM_ATTR_ANSWER])
 
87
                answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
 
88
 
 
89
        if (buf_len > sizeof(struct wl1271_command))
 
90
                return -EMSGSIZE;
 
91
 
 
92
        mutex_lock(&wl->mutex);
 
93
 
 
94
        if (wl->state == WL1271_STATE_OFF) {
 
95
                ret = -EINVAL;
 
96
                goto out;
 
97
        }
 
98
 
 
99
        ret = wl1271_ps_elp_wakeup(wl);
 
100
        if (ret < 0)
 
101
                goto out;
 
102
 
 
103
        ret = wl1271_cmd_test(wl, buf, buf_len, answer);
 
104
        if (ret < 0) {
 
105
                wl1271_warning("testmode cmd test failed: %d", ret);
 
106
                goto out_sleep;
 
107
        }
 
108
 
 
109
        if (answer) {
 
110
                len = nla_total_size(buf_len);
 
111
                skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
 
112
                if (!skb) {
 
113
                        ret = -ENOMEM;
 
114
                        goto out_sleep;
 
115
                }
 
116
 
 
117
                NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
 
118
                ret = cfg80211_testmode_reply(skb);
 
119
                if (ret < 0)
 
120
                        goto out_sleep;
 
121
        }
 
122
 
 
123
out_sleep:
 
124
        wl1271_ps_elp_sleep(wl);
 
125
out:
 
126
        mutex_unlock(&wl->mutex);
 
127
 
 
128
        return ret;
 
129
 
 
130
nla_put_failure:
 
131
        kfree_skb(skb);
 
132
        ret = -EMSGSIZE;
 
133
        goto out_sleep;
 
134
}
 
135
 
 
136
static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
 
137
{
 
138
        int ret;
 
139
        struct wl1271_command *cmd;
 
140
        struct sk_buff *skb;
 
141
        u8 ie_id;
 
142
 
 
143
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
 
144
 
 
145
        if (!tb[WL1271_TM_ATTR_IE_ID])
 
146
                return -EINVAL;
 
147
 
 
148
        ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
 
149
 
 
150
        mutex_lock(&wl->mutex);
 
151
 
 
152
        if (wl->state == WL1271_STATE_OFF) {
 
153
                ret = -EINVAL;
 
154
                goto out;
 
155
        }
 
156
 
 
157
        ret = wl1271_ps_elp_wakeup(wl);
 
158
        if (ret < 0)
 
159
                goto out;
 
160
 
 
161
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 
162
        if (!cmd) {
 
163
                ret = -ENOMEM;
 
164
                goto out_sleep;
 
165
        }
 
166
 
 
167
        ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
 
168
        if (ret < 0) {
 
169
                wl1271_warning("testmode cmd interrogate failed: %d", ret);
 
170
                goto out_free;
 
171
        }
 
172
 
 
173
        skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
 
174
        if (!skb) {
 
175
                ret = -ENOMEM;
 
176
                goto out_free;
 
177
        }
 
178
 
 
179
        NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
 
180
        ret = cfg80211_testmode_reply(skb);
 
181
        if (ret < 0)
 
182
                goto out_free;
 
183
 
 
184
out_free:
 
185
        kfree(cmd);
 
186
out_sleep:
 
187
        wl1271_ps_elp_sleep(wl);
 
188
out:
 
189
        mutex_unlock(&wl->mutex);
 
190
 
 
191
        return ret;
 
192
 
 
193
nla_put_failure:
 
194
        kfree_skb(skb);
 
195
        ret = -EMSGSIZE;
 
196
        goto out_free;
 
197
}
 
198
 
 
199
static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
 
200
{
 
201
        int buf_len, ret;
 
202
        void *buf;
 
203
        u8 ie_id;
 
204
 
 
205
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
 
206
 
 
207
        if (!tb[WL1271_TM_ATTR_DATA])
 
208
                return -EINVAL;
 
209
        if (!tb[WL1271_TM_ATTR_IE_ID])
 
210
                return -EINVAL;
 
211
 
 
212
        ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
 
213
        buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
 
214
        buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
 
215
 
 
216
        if (buf_len > sizeof(struct wl1271_command))
 
217
                return -EMSGSIZE;
 
218
 
 
219
        mutex_lock(&wl->mutex);
 
220
        ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
 
221
        mutex_unlock(&wl->mutex);
 
222
 
 
223
        if (ret < 0) {
 
224
                wl1271_warning("testmode cmd configure failed: %d", ret);
 
225
                return ret;
 
226
        }
 
227
 
 
228
        return 0;
 
229
}
 
230
 
 
231
static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
 
232
{
 
233
        u32 val;
 
234
        int ret;
 
235
 
 
236
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
 
237
 
 
238
        if (!tb[WL1271_TM_ATTR_PLT_MODE])
 
239
                return -EINVAL;
 
240
 
 
241
        val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
 
242
 
 
243
        switch (val) {
 
244
        case 0:
 
245
                ret = wl1271_plt_stop(wl);
 
246
                break;
 
247
        case 1:
 
248
                ret = wl1271_plt_start(wl);
 
249
                break;
 
250
        default:
 
251
                ret = -EINVAL;
 
252
                break;
 
253
        }
 
254
 
 
255
        return ret;
 
256
}
 
257
 
 
258
static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
 
259
{
 
260
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
 
261
 
 
262
        wl12xx_queue_recovery_work(wl);
 
263
 
 
264
        return 0;
 
265
}
 
266
 
 
267
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
 
268
{
 
269
        struct wl1271 *wl = hw->priv;
 
270
        struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
 
271
        int err;
 
272
 
 
273
        err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
 
274
        if (err)
 
275
                return err;
 
276
 
 
277
        if (!tb[WL1271_TM_ATTR_CMD_ID])
 
278
                return -EINVAL;
 
279
 
 
280
        switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
 
281
        case WL1271_TM_CMD_TEST:
 
282
                return wl1271_tm_cmd_test(wl, tb);
 
283
        case WL1271_TM_CMD_INTERROGATE:
 
284
                return wl1271_tm_cmd_interrogate(wl, tb);
 
285
        case WL1271_TM_CMD_CONFIGURE:
 
286
                return wl1271_tm_cmd_configure(wl, tb);
 
287
        case WL1271_TM_CMD_SET_PLT_MODE:
 
288
                return wl1271_tm_cmd_set_plt_mode(wl, tb);
 
289
        case WL1271_TM_CMD_RECOVER:
 
290
                return wl1271_tm_cmd_recover(wl, tb);
 
291
        default:
 
292
                return -EOPNOTSUPP;
 
293
        }
 
294
}