~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-proposed

« back to all changes in this revision

Viewing changes to updates/compat-wireless-2.6.36/drivers/net/wireless/wl12xx/wl1271_testmode.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

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 "wl1271_testmode.h"
24
 
 
25
 
#include <linux/slab.h>
26
 
#include <net/genetlink.h>
27
 
 
28
 
#include "wl1271.h"
29
 
#include "wl1271_acx.h"
30
 
 
31
 
#define WL1271_TM_MAX_DATA_LENGTH 1024
32
 
 
33
 
enum wl1271_tm_commands {
34
 
        WL1271_TM_CMD_UNSPEC,
35
 
        WL1271_TM_CMD_TEST,
36
 
        WL1271_TM_CMD_INTERROGATE,
37
 
        WL1271_TM_CMD_CONFIGURE,
38
 
        WL1271_TM_CMD_NVS_PUSH,
39
 
        WL1271_TM_CMD_SET_PLT_MODE,
40
 
 
41
 
        __WL1271_TM_CMD_AFTER_LAST
42
 
};
43
 
#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
44
 
 
45
 
enum wl1271_tm_attrs {
46
 
        WL1271_TM_ATTR_UNSPEC,
47
 
        WL1271_TM_ATTR_CMD_ID,
48
 
        WL1271_TM_ATTR_ANSWER,
49
 
        WL1271_TM_ATTR_DATA,
50
 
        WL1271_TM_ATTR_IE_ID,
51
 
        WL1271_TM_ATTR_PLT_MODE,
52
 
 
53
 
        __WL1271_TM_ATTR_AFTER_LAST
54
 
};
55
 
#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
56
 
 
57
 
static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
58
 
        [WL1271_TM_ATTR_CMD_ID] =       { .type = NLA_U32 },
59
 
        [WL1271_TM_ATTR_ANSWER] =       { .type = NLA_U8 },
60
 
        [WL1271_TM_ATTR_DATA] =         { .type = NLA_BINARY,
61
 
                                          .len = WL1271_TM_MAX_DATA_LENGTH },
62
 
        [WL1271_TM_ATTR_IE_ID] =        { .type = NLA_U32 },
63
 
        [WL1271_TM_ATTR_PLT_MODE] =     { .type = NLA_U32 },
64
 
};
65
 
 
66
 
 
67
 
static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
68
 
{
69
 
        int buf_len, ret, len;
70
 
        struct sk_buff *skb;
71
 
        void *buf;
72
 
        u8 answer = 0;
73
 
 
74
 
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
75
 
 
76
 
        if (!tb[WL1271_TM_ATTR_DATA])
77
 
                return -EINVAL;
78
 
 
79
 
        buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
80
 
        buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
81
 
 
82
 
        if (tb[WL1271_TM_ATTR_ANSWER])
83
 
                answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
84
 
 
85
 
        if (buf_len > sizeof(struct wl1271_command))
86
 
                return -EMSGSIZE;
87
 
 
88
 
        mutex_lock(&wl->mutex);
89
 
        ret = wl1271_cmd_test(wl, buf, buf_len, answer);
90
 
        mutex_unlock(&wl->mutex);
91
 
 
92
 
        if (ret < 0) {
93
 
                wl1271_warning("testmode cmd test failed: %d", ret);
94
 
                return ret;
95
 
        }
96
 
 
97
 
        if (answer) {
98
 
                len = nla_total_size(buf_len);
99
 
                skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
100
 
                if (!skb)
101
 
                        return -ENOMEM;
102
 
 
103
 
                NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
104
 
                ret = cfg80211_testmode_reply(skb);
105
 
                if (ret < 0)
106
 
                        return ret;
107
 
        }
108
 
 
109
 
        return 0;
110
 
 
111
 
nla_put_failure:
112
 
        kfree_skb(skb);
113
 
        return -EMSGSIZE;
114
 
}
115
 
 
116
 
static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
117
 
{
118
 
        int ret;
119
 
        struct wl1271_command *cmd;
120
 
        struct sk_buff *skb;
121
 
        u8 ie_id;
122
 
 
123
 
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
124
 
 
125
 
        if (!tb[WL1271_TM_ATTR_IE_ID])
126
 
                return -EINVAL;
127
 
 
128
 
        ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
129
 
 
130
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
131
 
        if (!cmd)
132
 
                return -ENOMEM;
133
 
 
134
 
        mutex_lock(&wl->mutex);
135
 
        ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
136
 
        mutex_unlock(&wl->mutex);
137
 
 
138
 
        if (ret < 0) {
139
 
                wl1271_warning("testmode cmd interrogate failed: %d", ret);
140
 
                return ret;
141
 
        }
142
 
 
143
 
        skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
144
 
        if (!skb)
145
 
                return -ENOMEM;
146
 
 
147
 
        NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
148
 
 
149
 
        return 0;
150
 
 
151
 
nla_put_failure:
152
 
        kfree_skb(skb);
153
 
        return -EMSGSIZE;
154
 
}
155
 
 
156
 
static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
157
 
{
158
 
        int buf_len, ret;
159
 
        void *buf;
160
 
        u8 ie_id;
161
 
 
162
 
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
163
 
 
164
 
        if (!tb[WL1271_TM_ATTR_DATA])
165
 
                return -EINVAL;
166
 
        if (!tb[WL1271_TM_ATTR_IE_ID])
167
 
                return -EINVAL;
168
 
 
169
 
        ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
170
 
        buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
171
 
        buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
172
 
 
173
 
        if (buf_len > sizeof(struct wl1271_command))
174
 
                return -EMSGSIZE;
175
 
 
176
 
        mutex_lock(&wl->mutex);
177
 
        ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
178
 
        mutex_unlock(&wl->mutex);
179
 
 
180
 
        if (ret < 0) {
181
 
                wl1271_warning("testmode cmd configure failed: %d", ret);
182
 
                return ret;
183
 
        }
184
 
 
185
 
        return 0;
186
 
}
187
 
 
188
 
static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
189
 
{
190
 
        int ret = 0;
191
 
        size_t len;
192
 
        void *buf;
193
 
 
194
 
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push");
195
 
 
196
 
        if (!tb[WL1271_TM_ATTR_DATA])
197
 
                return -EINVAL;
198
 
 
199
 
        buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
200
 
        len = nla_len(tb[WL1271_TM_ATTR_DATA]);
201
 
 
202
 
        /*
203
 
         * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
204
 
         * configurations) can be removed when those NVS files stop floating
205
 
         * around.
206
 
         */
207
 
        if (len != sizeof(struct wl1271_nvs_file) &&
208
 
            (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
209
 
             wl1271_11a_enabled())) {
210
 
                wl1271_error("nvs size is not as expected: %zu != %zu",
211
 
                             len, sizeof(struct wl1271_nvs_file));
212
 
                return -EMSGSIZE;
213
 
        }
214
 
 
215
 
        mutex_lock(&wl->mutex);
216
 
 
217
 
        kfree(wl->nvs);
218
 
 
219
 
        wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
220
 
        if (!wl->nvs) {
221
 
                wl1271_error("could not allocate memory for the nvs file");
222
 
                ret = -ENOMEM;
223
 
                goto out;
224
 
        }
225
 
 
226
 
        memcpy(wl->nvs, buf, len);
227
 
 
228
 
        wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
229
 
 
230
 
out:
231
 
        mutex_unlock(&wl->mutex);
232
 
 
233
 
        return ret;
234
 
}
235
 
 
236
 
static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
237
 
{
238
 
        u32 val;
239
 
        int ret;
240
 
 
241
 
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
242
 
 
243
 
        if (!tb[WL1271_TM_ATTR_PLT_MODE])
244
 
                return -EINVAL;
245
 
 
246
 
        val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
247
 
 
248
 
        switch (val) {
249
 
        case 0:
250
 
                ret = wl1271_plt_stop(wl);
251
 
                break;
252
 
        case 1:
253
 
                ret = wl1271_plt_start(wl);
254
 
                break;
255
 
        default:
256
 
                ret = -EINVAL;
257
 
                break;
258
 
        }
259
 
 
260
 
        return ret;
261
 
}
262
 
 
263
 
int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
264
 
{
265
 
        struct wl1271 *wl = hw->priv;
266
 
        struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
267
 
        int err;
268
 
 
269
 
        err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
270
 
        if (err)
271
 
                return err;
272
 
 
273
 
        if (!tb[WL1271_TM_ATTR_CMD_ID])
274
 
                return -EINVAL;
275
 
 
276
 
        switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
277
 
        case WL1271_TM_CMD_TEST:
278
 
                return wl1271_tm_cmd_test(wl, tb);
279
 
        case WL1271_TM_CMD_INTERROGATE:
280
 
                return wl1271_tm_cmd_interrogate(wl, tb);
281
 
        case WL1271_TM_CMD_CONFIGURE:
282
 
                return wl1271_tm_cmd_configure(wl, tb);
283
 
        case WL1271_TM_CMD_NVS_PUSH:
284
 
                return wl1271_tm_cmd_nvs_push(wl, tb);
285
 
        case WL1271_TM_CMD_SET_PLT_MODE:
286
 
                return wl1271_tm_cmd_set_plt_mode(wl, tb);
287
 
        default:
288
 
                return -EOPNOTSUPP;
289
 
        }
290
 
}