blob: 46e5ea48651bbe7e5ac78f6fc3be693b18a10d65 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2009 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
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/crc7.h>
27#include <linux/spi/spi.h>
28#include <linux/etherdevice.h>
29
30#include "wl1271.h"
31#include "wl1271_reg.h"
32#include "wl1271_spi.h"
33#include "wl1271_acx.h"
34#include "wl12xx_80211.h"
35#include "wl1271_cmd.h"
36
37/*
38 * send command to firmware
39 *
40 * @wl: wl struct
41 * @id: command id
42 * @buf: buffer containing the command, must work with dma
43 * @len: length of the buffer
44 */
45int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
46{
47 struct wl1271_cmd_header *cmd;
48 unsigned long timeout;
49 u32 intr;
50 int ret = 0;
51
52 cmd = buf;
Luciano Coelhod0f63b22009-10-15 10:33:29 +030053 cmd->id = cpu_to_le16(id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030054 cmd->status = 0;
55
56 WARN_ON(len % 4 != 0);
57
Juuso Oikarinen74621412009-10-12 15:08:54 +030058 wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030059
Juuso Oikarinen74621412009-10-12 15:08:54 +030060 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030061
62 timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
63
Juuso Oikarinen74621412009-10-12 15:08:54 +030064 intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030065 while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
66 if (time_after(jiffies, timeout)) {
67 wl1271_error("command complete timeout");
68 ret = -ETIMEDOUT;
69 goto out;
70 }
71
72 msleep(1);
73
Juuso Oikarinen74621412009-10-12 15:08:54 +030074 intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030075 }
76
Juuso Oikarinen3b775b42009-11-02 20:22:10 +020077 /* read back the status code of the command */
78 wl1271_spi_read(wl, wl->cmd_box_addr, cmd,
79 sizeof(struct wl1271_cmd_header), false);
80
81 if (cmd->status != CMD_STATUS_SUCCESS) {
82 wl1271_error("command execute failure %d", cmd->status);
83 ret = -EIO;
84 }
85
Juuso Oikarinen74621412009-10-12 15:08:54 +030086 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030087 WL1271_ACX_INTR_CMD_COMPLETE);
88
89out:
90 return ret;
91}
92
Luciano Coelho938e30c2009-10-15 10:33:27 +030093static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030094{
95 struct wl1271_cmd_cal_channel_tune *cmd;
96 int ret = 0;
97
98 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
99 if (!cmd)
100 return -ENOMEM;
101
102 cmd->test.id = TEST_CMD_CHANNEL_TUNE;
103
104 cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
105 /* set up any channel, 7 is in the middle of the range */
106 cmd->channel = 7;
107
108 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
109 if (ret < 0)
110 wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
111
112 kfree(cmd);
113 return ret;
114}
115
Luciano Coelho938e30c2009-10-15 10:33:27 +0300116static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300117{
118 struct wl1271_cmd_cal_update_ref_point *cmd;
119 int ret = 0;
120
121 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
122 if (!cmd)
123 return -ENOMEM;
124
125 cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
126
127 /* FIXME: still waiting for the correct values */
128 cmd->ref_power = 0;
129 cmd->ref_detector = 0;
130
131 cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G;
132
133 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
134 if (ret < 0)
135 wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
136
137 kfree(cmd);
138 return ret;
139}
140
Luciano Coelho938e30c2009-10-15 10:33:27 +0300141static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300142{
143 struct wl1271_cmd_cal_p2g *cmd;
144 int ret = 0;
145
146 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
147 if (!cmd)
148 return -ENOMEM;
149
150 cmd->test.id = TEST_CMD_P2G_CAL;
151
152 cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
153
154 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
155 if (ret < 0)
156 wl1271_warning("TEST_CMD_P2G_CAL failed");
157
158 kfree(cmd);
159 return ret;
160}
161
Luciano Coelho938e30c2009-10-15 10:33:27 +0300162static int wl1271_cmd_cal(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300163{
164 /*
165 * FIXME: we must make sure that we're not sleeping when calibration
166 * is done
167 */
168 int ret;
169
170 wl1271_notice("performing tx calibration");
171
172 ret = wl1271_cmd_cal_channel_tune(wl);
173 if (ret < 0)
174 return ret;
175
176 ret = wl1271_cmd_cal_update_ref_point(wl);
177 if (ret < 0)
178 return ret;
179
180 ret = wl1271_cmd_cal_p2g(wl);
181 if (ret < 0)
182 return ret;
183
184 return ret;
185}
186
Juuso Oikarinend94cd292009-10-08 21:56:25 +0300187int wl1271_cmd_join(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300188{
189 static bool do_cal = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300190 struct wl1271_cmd_join *join;
191 int ret, i;
192 u8 *bssid;
193
194 /* FIXME: remove when we get calibration from the factory */
195 if (do_cal) {
196 ret = wl1271_cmd_cal(wl);
197 if (ret < 0)
198 wl1271_warning("couldn't calibrate");
199 else
200 do_cal = false;
201 }
202
Luciano Coelhod6e19d132009-10-12 15:08:43 +0300203 /* FIXME: This is a workaround, because with the current stack, we
204 * cannot know when we have disassociated. So, if we have already
205 * joined, we disconnect before joining again. */
206 if (wl->joined) {
207 ret = wl1271_cmd_disconnect(wl);
208 if (ret < 0) {
209 wl1271_error("failed to disconnect before rejoining");
210 goto out;
211 }
212
213 wl->joined = false;
214 }
215
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300216 join = kzalloc(sizeof(*join), GFP_KERNEL);
217 if (!join) {
218 ret = -ENOMEM;
219 goto out;
220 }
221
222 wl1271_debug(DEBUG_CMD, "cmd join");
223
224 /* Reverse order BSSID */
225 bssid = (u8 *) &join->bssid_lsb;
226 for (i = 0; i < ETH_ALEN; i++)
227 bssid[i] = wl->bssid[ETH_ALEN - i - 1];
228
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300229 join->rx_config_options = cpu_to_le32(wl->rx_config);
230 join->rx_filter_options = cpu_to_le32(wl->rx_filter);
Teemu Paasikivia4102642009-10-13 12:47:51 +0300231 join->bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300232
Luciano Coelho64a7f672009-10-08 21:56:28 +0300233 /*
234 * FIXME: disable temporarily all filters because after commit
235 * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
236 * association. The filter logic needs to be implemented properly
237 * and once that is done, this hack can be removed.
238 */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300239 join->rx_config_options = cpu_to_le32(0);
240 join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER);
Luciano Coelho64a7f672009-10-08 21:56:28 +0300241
Teemu Paasikivia4102642009-10-13 12:47:51 +0300242 if (wl->band == IEEE80211_BAND_2GHZ)
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300243 join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS |
244 CONF_HW_BIT_RATE_2MBPS |
245 CONF_HW_BIT_RATE_5_5MBPS |
246 CONF_HW_BIT_RATE_11MBPS);
Teemu Paasikivia4102642009-10-13 12:47:51 +0300247 else {
248 join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300249 join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS |
250 CONF_HW_BIT_RATE_12MBPS |
251 CONF_HW_BIT_RATE_24MBPS);
Teemu Paasikivia4102642009-10-13 12:47:51 +0300252 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300253
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300254 join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT);
Luciano Coelhoae751ba2009-10-12 15:08:57 +0300255 join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
Teemu Paasikivia4102642009-10-13 12:47:51 +0300256
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300257 join->channel = wl->channel;
258 join->ssid_len = wl->ssid_len;
259 memcpy(join->ssid, wl->ssid, wl->ssid_len);
260 join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
261
262 /* increment the session counter */
263 wl->session_counter++;
264 if (wl->session_counter >= SESSION_COUNTER_MAX)
265 wl->session_counter = 0;
266
267 join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
268
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300269 /* reset TX security counters */
270 wl->tx_security_last_seq = 0;
271 wl->tx_security_seq_16 = 0;
272 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300273
274 ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
275 if (ret < 0) {
276 wl1271_error("failed to initiate cmd join");
277 goto out_free;
278 }
279
Luciano Coelhod6e19d132009-10-12 15:08:43 +0300280 wl->joined = true;
281
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300282 /*
283 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
284 * simplify locking we just sleep instead, for now
285 */
Juuso Oikarinend94cd292009-10-08 21:56:25 +0300286 msleep(10);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300287
288out_free:
289 kfree(join);
290
291out:
292 return ret;
293}
294
295/**
296 * send test command to firmware
297 *
298 * @wl: wl struct
299 * @buf: buffer containing the command, with all headers, must work with dma
300 * @len: length of the buffer
301 * @answer: is answer needed
302 */
303int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
304{
305 int ret;
306
307 wl1271_debug(DEBUG_CMD, "cmd test");
308
309 ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len);
310
311 if (ret < 0) {
312 wl1271_warning("TEST command failed");
313 return ret;
314 }
315
316 if (answer) {
317 struct wl1271_command *cmd_answer;
318
319 /*
320 * The test command got in, we can read the answer.
321 * The answer would be a wl1271_command, where the
322 * parameter array contains the actual answer.
323 */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300324 wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300325
326 cmd_answer = buf;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300327 }
328
329 return 0;
330}
331
332/**
333 * read acx from firmware
334 *
335 * @wl: wl struct
336 * @id: acx id
337 * @buf: buffer for the response, including all headers, must work with dma
338 * @len: lenght of buf
339 */
340int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
341{
342 struct acx_header *acx = buf;
343 int ret;
344
345 wl1271_debug(DEBUG_CMD, "cmd interrogate");
346
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300347 acx->id = cpu_to_le16(id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300348
349 /* payload length, does not include any headers */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300350 acx->len = cpu_to_le16(len - sizeof(*acx));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300351
352 ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
353 if (ret < 0) {
354 wl1271_error("INTERROGATE command failed");
355 goto out;
356 }
357
358 /* the interrogate command got in, we can read the answer */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300359 wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361out:
362 return ret;
363}
364
365/**
366 * write acx value to firmware
367 *
368 * @wl: wl struct
369 * @id: acx id
370 * @buf: buffer containing acx, including all headers, must work with dma
371 * @len: length of buf
372 */
373int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
374{
375 struct acx_header *acx = buf;
376 int ret;
377
378 wl1271_debug(DEBUG_CMD, "cmd configure");
379
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300380 acx->id = cpu_to_le16(id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381
382 /* payload length, does not include any headers */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300383 acx->len = cpu_to_le16(len - sizeof(*acx));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300384
385 ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len);
386 if (ret < 0) {
387 wl1271_warning("CONFIGURE command NOK");
388 return ret;
389 }
390
391 return 0;
392}
393
394int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
395{
396 struct cmd_enabledisable_path *cmd;
397 int ret;
398 u16 cmd_rx, cmd_tx;
399
400 wl1271_debug(DEBUG_CMD, "cmd data path");
401
402 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
403 if (!cmd) {
404 ret = -ENOMEM;
405 goto out;
406 }
407
408 cmd->channel = channel;
409
410 if (enable) {
411 cmd_rx = CMD_ENABLE_RX;
412 cmd_tx = CMD_ENABLE_TX;
413 } else {
414 cmd_rx = CMD_DISABLE_RX;
415 cmd_tx = CMD_DISABLE_TX;
416 }
417
418 ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
419 if (ret < 0) {
420 wl1271_error("rx %s cmd for channel %d failed",
421 enable ? "start" : "stop", channel);
422 goto out;
423 }
424
425 wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
426 enable ? "start" : "stop", channel);
427
428 ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
429 if (ret < 0) {
430 wl1271_error("tx %s cmd for channel %d failed",
431 enable ? "start" : "stop", channel);
432 return ret;
433 }
434
435 wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
436 enable ? "start" : "stop", channel);
437
438out:
439 kfree(cmd);
440 return ret;
441}
442
443int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
444{
445 struct wl1271_cmd_ps_params *ps_params = NULL;
446 int ret = 0;
447
448 /* FIXME: this should be in ps.c */
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300449 ret = wl1271_acx_wake_up_conditions(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450 if (ret < 0) {
451 wl1271_error("couldn't set wake up conditions");
452 goto out;
453 }
454
455 wl1271_debug(DEBUG_CMD, "cmd set ps mode");
456
457 ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
458 if (!ps_params) {
459 ret = -ENOMEM;
460 goto out;
461 }
462
463 ps_params->ps_mode = ps_mode;
464 ps_params->send_null_data = 1;
465 ps_params->retries = 5;
466 ps_params->hang_over_period = 128;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300467 ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
469 ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
470 sizeof(*ps_params));
471 if (ret < 0) {
472 wl1271_error("cmd set_ps_mode failed");
473 goto out;
474 }
475
476out:
477 kfree(ps_params);
478 return ret;
479}
480
481int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
482 size_t len)
483{
484 struct cmd_read_write_memory *cmd;
485 int ret = 0;
486
487 wl1271_debug(DEBUG_CMD, "cmd read memory");
488
489 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
490 if (!cmd) {
491 ret = -ENOMEM;
492 goto out;
493 }
494
495 WARN_ON(len > MAX_READ_SIZE);
496 len = min_t(size_t, len, MAX_READ_SIZE);
497
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300498 cmd->addr = cpu_to_le32(addr);
499 cmd->size = cpu_to_le32(len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300500
501 ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
502 if (ret < 0) {
503 wl1271_error("read memory command failed: %d", ret);
504 goto out;
505 }
506
507 /* the read command got in, we can now read the answer */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300508 wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300509 memcpy(answer, cmd->value, len);
510
511out:
512 kfree(cmd);
513 return ret;
514}
515
516int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300517 u8 active_scan, u8 high_prio, u8 band,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518 u8 probe_requests)
519{
520
521 struct wl1271_cmd_trigger_scan_to *trigger = NULL;
522 struct wl1271_cmd_scan *params = NULL;
Teemu Paasikivi311494c2009-10-13 12:47:49 +0300523 struct ieee80211_channel *channels;
524 int i, j, n_ch, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525 u16 scan_options = 0;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300526 u8 ieee_band;
527
528 if (band == WL1271_SCAN_BAND_2_4_GHZ)
529 ieee_band = IEEE80211_BAND_2GHZ;
530 else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
531 ieee_band = IEEE80211_BAND_2GHZ;
532 else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
533 ieee_band = IEEE80211_BAND_5GHZ;
534 else
535 return -EINVAL;
536
537 if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
538 return -EINVAL;
539
540 channels = wl->hw->wiphy->bands[ieee_band]->channels;
541 n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300542
543 if (wl->scanning)
544 return -EINVAL;
545
546 params = kzalloc(sizeof(*params), GFP_KERNEL);
547 if (!params)
548 return -ENOMEM;
549
550 params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
551 params->params.rx_filter_options =
552 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
553
554 if (!active_scan)
555 scan_options |= WL1271_SCAN_OPT_PASSIVE;
556 if (high_prio)
557 scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300558 params->params.scan_options = cpu_to_le16(scan_options);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300560 params->params.num_probe_requests = probe_requests;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300561 /* Let the fw autodetect suitable tx_rate for probes */
562 params->params.tx_rate = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300563 params->params.tid_trigger = 0;
564 params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
565
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300566 if (band == WL1271_SCAN_BAND_DUAL)
567 params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
568 else
569 params->params.band = band;
570
Teemu Paasikivi311494c2009-10-13 12:47:49 +0300571 for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
572 if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
573 params->channels[j].min_duration =
574 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
575 params->channels[j].max_duration =
576 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
577 memset(&params->channels[j].bssid_lsb, 0xff, 4);
578 memset(&params->channels[j].bssid_msb, 0xff, 2);
579 params->channels[j].early_termination = 0;
580 params->channels[j].tx_power_att =
581 WL1271_SCAN_CURRENT_TX_PWR;
582 params->channels[j].channel = channels[i].hw_value;
583 j++;
584 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300585 }
586
Teemu Paasikivi311494c2009-10-13 12:47:49 +0300587 params->params.num_channels = j;
588
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300589 if (len && ssid) {
590 params->params.ssid_len = len;
591 memcpy(params->params.ssid, ssid, len);
592 }
593
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300594 ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300595 if (ret < 0) {
596 wl1271_error("PROBE request template failed");
597 goto out;
598 }
599
600 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
601 if (!trigger) {
602 ret = -ENOMEM;
603 goto out;
604 }
605
606 /* disable the timeout */
607 trigger->timeout = 0;
608
609 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
610 sizeof(*trigger));
611 if (ret < 0) {
612 wl1271_error("trigger scan to failed for hw scan");
613 goto out;
614 }
615
616 wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
617
618 wl->scanning = true;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300619 if (wl1271_11a_enabled()) {
620 wl->scan.state = band;
621 if (band == WL1271_SCAN_BAND_DUAL) {
622 wl->scan.active = active_scan;
623 wl->scan.high_prio = high_prio;
624 wl->scan.probe_requests = probe_requests;
625 if (len && ssid) {
626 wl->scan.ssid_len = len;
627 memcpy(wl->scan.ssid, ssid, len);
628 } else
629 wl->scan.ssid_len = 0;
630 }
631 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300632
633 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
634 if (ret < 0) {
635 wl1271_error("SCAN failed");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636 wl->scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637 goto out;
638 }
639
640out:
641 kfree(params);
642 return ret;
643}
644
645int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
646 void *buf, size_t buf_len)
647{
648 struct wl1271_cmd_template_set *cmd;
649 int ret = 0;
650
651 wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
652
653 WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
654 buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
655
656 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
657 if (!cmd) {
658 ret = -ENOMEM;
659 goto out;
660 }
661
662 cmd->len = cpu_to_le16(buf_len);
663 cmd->template_type = template_id;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300664 cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates);
Juuso Oikarinen45b531a2009-10-13 12:47:41 +0300665 cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
666 cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667
668 if (buf)
669 memcpy(cmd->template_data, buf, buf_len);
670
671 ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd));
672 if (ret < 0) {
673 wl1271_warning("cmd set_template failed: %d", ret);
674 goto out_free;
675 }
676
677out_free:
678 kfree(cmd);
679
680out:
681 return ret;
682}
683
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300684static int wl1271_build_basic_rates(char *rates, u8 band)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685{
686 u8 index = 0;
687
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300688 if (band == IEEE80211_BAND_2GHZ) {
689 rates[index++] =
690 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
691 rates[index++] =
692 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
693 rates[index++] =
694 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
695 rates[index++] =
696 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
697 } else if (band == IEEE80211_BAND_5GHZ) {
698 rates[index++] =
699 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
700 rates[index++] =
701 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
702 rates[index++] =
703 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
704 } else {
705 wl1271_error("build_basic_rates invalid band: %d", band);
706 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300707
708 return index;
709}
710
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300711static int wl1271_build_extended_rates(char *rates, u8 band)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712{
713 u8 index = 0;
714
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300715 if (band == IEEE80211_BAND_2GHZ) {
716 rates[index++] = IEEE80211_OFDM_RATE_6MB;
717 rates[index++] = IEEE80211_OFDM_RATE_9MB;
718 rates[index++] = IEEE80211_OFDM_RATE_12MB;
719 rates[index++] = IEEE80211_OFDM_RATE_18MB;
720 rates[index++] = IEEE80211_OFDM_RATE_24MB;
721 rates[index++] = IEEE80211_OFDM_RATE_36MB;
722 rates[index++] = IEEE80211_OFDM_RATE_48MB;
723 rates[index++] = IEEE80211_OFDM_RATE_54MB;
724 } else if (band == IEEE80211_BAND_5GHZ) {
725 rates[index++] =
726 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
727 rates[index++] =
728 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
729 rates[index++] =
730 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
731 rates[index++] =
732 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
733 rates[index++] =
734 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
735 rates[index++] =
736 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
737 } else {
738 wl1271_error("build_basic_rates invalid band: %d", band);
739 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740
741 return index;
742}
743
744int wl1271_cmd_build_null_data(struct wl1271 *wl)
745{
746 struct wl12xx_null_data_template template;
747
748 if (!is_zero_ether_addr(wl->bssid)) {
749 memcpy(template.header.da, wl->bssid, ETH_ALEN);
750 memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
751 } else {
752 memset(template.header.da, 0xff, ETH_ALEN);
753 memset(template.header.bssid, 0xff, ETH_ALEN);
754 }
755
756 memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
757 template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
Juuso Oikarinen7a380792009-10-15 10:33:26 +0300758 IEEE80211_STYPE_NULLFUNC |
759 IEEE80211_FCTL_TODS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760
761 return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
762 sizeof(template));
763
764}
765
766int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
767{
768 struct wl12xx_ps_poll_template template;
769
770 memcpy(template.bssid, wl->bssid, ETH_ALEN);
771 memcpy(template.ta, wl->mac_addr, ETH_ALEN);
Juuso Oikarinenc3fea192009-10-08 21:56:22 +0300772
773 /* aid in PS-Poll has its two MSBs each set to 1 */
774 template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
775
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300776 template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
777
778 return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
779 sizeof(template));
780
781}
782
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300783int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
784 u8 band)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785{
786 struct wl12xx_probe_req_template template;
787 struct wl12xx_ie_rates *rates;
788 char *ptr;
789 u16 size;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300790 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791
792 ptr = (char *)&template;
793 size = sizeof(struct ieee80211_header);
794
795 memset(template.header.da, 0xff, ETH_ALEN);
796 memset(template.header.bssid, 0xff, ETH_ALEN);
797 memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
798 template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
799
800 /* IEs */
801 /* SSID */
802 template.ssid.header.id = WLAN_EID_SSID;
803 template.ssid.header.len = ssid_len;
804 if (ssid_len && ssid)
805 memcpy(template.ssid.ssid, ssid, ssid_len);
806 size += sizeof(struct wl12xx_ie_header) + ssid_len;
807 ptr += size;
808
809 /* Basic Rates */
810 rates = (struct wl12xx_ie_rates *)ptr;
811 rates->header.id = WLAN_EID_SUPP_RATES;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300812 rates->header.len = wl1271_build_basic_rates(rates->rates, band);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300813 size += sizeof(struct wl12xx_ie_header) + rates->header.len;
814 ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
815
816 /* Extended rates */
817 rates = (struct wl12xx_ie_rates *)ptr;
818 rates->header.id = WLAN_EID_EXT_SUPP_RATES;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300819 rates->header.len = wl1271_build_extended_rates(rates->rates, band);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820 size += sizeof(struct wl12xx_ie_header) + rates->header.len;
821
822 wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
823
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300824 if (band == IEEE80211_BAND_2GHZ)
825 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
826 &template, size);
827 else
828 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
829 &template, size);
830 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831}
832
833int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
834{
835 struct wl1271_cmd_set_keys *cmd;
836 int ret = 0;
837
838 wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
839
840 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
841 if (!cmd) {
842 ret = -ENOMEM;
843 goto out;
844 }
845
846 cmd->id = id;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300847 cmd->key_action = cpu_to_le16(KEY_SET_ID);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848 cmd->key_type = KEY_WEP;
849
850 ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
851 if (ret < 0) {
852 wl1271_warning("cmd set_default_wep_key failed: %d", ret);
853 goto out;
854 }
855
856out:
857 kfree(cmd);
858
859 return ret;
860}
861
862int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300863 u8 key_size, const u8 *key, const u8 *addr,
864 u32 tx_seq_32, u16 tx_seq_16)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300865{
866 struct wl1271_cmd_set_keys *cmd;
867 int ret = 0;
868
869 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
870 if (!cmd) {
871 ret = -ENOMEM;
872 goto out;
873 }
874
875 if (key_type != KEY_WEP)
876 memcpy(cmd->addr, addr, ETH_ALEN);
877
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300878 cmd->key_action = cpu_to_le16(action);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300879 cmd->key_size = key_size;
880 cmd->key_type = key_type;
881
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300882 cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
883 cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300884
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300885 /* we have only one SSID profile */
886 cmd->ssid_profile = 0;
887
888 cmd->id = id;
889
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890 if (key_type == KEY_TKIP) {
891 /*
892 * We get the key in the following form:
893 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
894 * but the target is expecting:
895 * TKIP - RX MIC - TX MIC
896 */
897 memcpy(cmd->key, key, 16);
898 memcpy(cmd->key + 16, key + 24, 8);
899 memcpy(cmd->key + 24, key + 16, 8);
900
901 } else {
902 memcpy(cmd->key, key, key_size);
903 }
904
905 wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
906
907 ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
908 if (ret < 0) {
909 wl1271_warning("could not set keys");
910 goto out;
911 }
912
913out:
914 kfree(cmd);
915
916 return ret;
917}
Luciano Coelho25a7dc62009-10-12 15:08:42 +0300918
919int wl1271_cmd_disconnect(struct wl1271 *wl)
920{
921 struct wl1271_cmd_disconnect *cmd;
922 int ret = 0;
923
924 wl1271_debug(DEBUG_CMD, "cmd disconnect");
925
926 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
927 if (!cmd) {
928 ret = -ENOMEM;
929 goto out;
930 }
931
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300932 cmd->rx_config_options = cpu_to_le32(wl->rx_config);
933 cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
Luciano Coelho25a7dc62009-10-12 15:08:42 +0300934 /* disconnect reason is not used in immediate disconnections */
935 cmd->type = DISCONNECT_IMMEDIATE;
936
937 ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd));
938 if (ret < 0) {
939 wl1271_error("failed to send disconnect command");
940 goto out_free;
941 }
942
943out_free:
944 kfree(cmd);
945
946out:
947 return ret;
948}