blob: 8acee5cf0e61d644703daaa3c03121d1d9a3b0a9 [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;
Juuso Oikarinenad150e92009-11-02 20:22:12 +020051 u16 status;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
53 cmd = buf;
Luciano Coelhod0f63b22009-10-15 10:33:29 +030054 cmd->id = cpu_to_le16(id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030055 cmd->status = 0;
56
57 WARN_ON(len % 4 != 0);
58
Juuso Oikarinen74621412009-10-12 15:08:54 +030059 wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030060
Juuso Oikarinen74621412009-10-12 15:08:54 +030061 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030062
63 timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
64
Juuso Oikarinen74621412009-10-12 15:08:54 +030065 intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030066 while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
67 if (time_after(jiffies, timeout)) {
68 wl1271_error("command complete timeout");
69 ret = -ETIMEDOUT;
70 goto out;
71 }
72
73 msleep(1);
74
Juuso Oikarinen74621412009-10-12 15:08:54 +030075 intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030076 }
77
Juuso Oikarinen3b775b42009-11-02 20:22:10 +020078 /* read back the status code of the command */
79 wl1271_spi_read(wl, wl->cmd_box_addr, cmd,
80 sizeof(struct wl1271_cmd_header), false);
81
Juuso Oikarinenad150e92009-11-02 20:22:12 +020082 status = le16_to_cpu(cmd->status);
83 if (status != CMD_STATUS_SUCCESS) {
84 wl1271_error("command execute failure %d", status);
Juuso Oikarinen3b775b42009-11-02 20:22:10 +020085 ret = -EIO;
86 }
87
Juuso Oikarinen74621412009-10-12 15:08:54 +030088 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030089 WL1271_ACX_INTR_CMD_COMPLETE);
90
91out:
92 return ret;
93}
94
Luciano Coelho938e30c2009-10-15 10:33:27 +030095static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030096{
97 struct wl1271_cmd_cal_channel_tune *cmd;
98 int ret = 0;
99
100 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
101 if (!cmd)
102 return -ENOMEM;
103
104 cmd->test.id = TEST_CMD_CHANNEL_TUNE;
105
106 cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
107 /* set up any channel, 7 is in the middle of the range */
108 cmd->channel = 7;
109
110 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
111 if (ret < 0)
112 wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
113
114 kfree(cmd);
115 return ret;
116}
117
Luciano Coelho938e30c2009-10-15 10:33:27 +0300118static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300119{
120 struct wl1271_cmd_cal_update_ref_point *cmd;
121 int ret = 0;
122
123 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
124 if (!cmd)
125 return -ENOMEM;
126
127 cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
128
129 /* FIXME: still waiting for the correct values */
130 cmd->ref_power = 0;
131 cmd->ref_detector = 0;
132
133 cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G;
134
135 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
136 if (ret < 0)
137 wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
138
139 kfree(cmd);
140 return ret;
141}
142
Luciano Coelho938e30c2009-10-15 10:33:27 +0300143static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300144{
145 struct wl1271_cmd_cal_p2g *cmd;
146 int ret = 0;
147
148 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
149 if (!cmd)
150 return -ENOMEM;
151
152 cmd->test.id = TEST_CMD_P2G_CAL;
153
154 cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
155
156 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
157 if (ret < 0)
158 wl1271_warning("TEST_CMD_P2G_CAL failed");
159
160 kfree(cmd);
161 return ret;
162}
163
Luciano Coelho938e30c2009-10-15 10:33:27 +0300164static int wl1271_cmd_cal(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300165{
166 /*
167 * FIXME: we must make sure that we're not sleeping when calibration
168 * is done
169 */
170 int ret;
171
172 wl1271_notice("performing tx calibration");
173
174 ret = wl1271_cmd_cal_channel_tune(wl);
175 if (ret < 0)
176 return ret;
177
178 ret = wl1271_cmd_cal_update_ref_point(wl);
179 if (ret < 0)
180 return ret;
181
182 ret = wl1271_cmd_cal_p2g(wl);
183 if (ret < 0)
184 return ret;
185
186 return ret;
187}
188
Juuso Oikarinend94cd292009-10-08 21:56:25 +0300189int wl1271_cmd_join(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300190{
191 static bool do_cal = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300192 struct wl1271_cmd_join *join;
193 int ret, i;
194 u8 *bssid;
195
196 /* FIXME: remove when we get calibration from the factory */
197 if (do_cal) {
198 ret = wl1271_cmd_cal(wl);
199 if (ret < 0)
200 wl1271_warning("couldn't calibrate");
201 else
202 do_cal = false;
203 }
204
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300205 /* FIXME: This is a workaround, because with the current stack, we
206 * cannot know when we have disassociated. So, if we have already
207 * joined, we disconnect before joining again. */
208 if (wl->joined) {
209 ret = wl1271_cmd_disconnect(wl);
210 if (ret < 0) {
211 wl1271_error("failed to disconnect before rejoining");
212 goto out;
213 }
214
215 wl->joined = false;
216 }
217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300218 join = kzalloc(sizeof(*join), GFP_KERNEL);
219 if (!join) {
220 ret = -ENOMEM;
221 goto out;
222 }
223
224 wl1271_debug(DEBUG_CMD, "cmd join");
225
226 /* Reverse order BSSID */
227 bssid = (u8 *) &join->bssid_lsb;
228 for (i = 0; i < ETH_ALEN; i++)
229 bssid[i] = wl->bssid[ETH_ALEN - i - 1];
230
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300231 join->rx_config_options = cpu_to_le32(wl->rx_config);
232 join->rx_filter_options = cpu_to_le32(wl->rx_filter);
Teemu Paasikivia4102642009-10-13 12:47:51 +0300233 join->bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300234
Luciano Coelho64a7f672009-10-08 21:56:28 +0300235 /*
236 * FIXME: disable temporarily all filters because after commit
237 * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
238 * association. The filter logic needs to be implemented properly
239 * and once that is done, this hack can be removed.
240 */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300241 join->rx_config_options = cpu_to_le32(0);
242 join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER);
Luciano Coelho64a7f672009-10-08 21:56:28 +0300243
Teemu Paasikivia4102642009-10-13 12:47:51 +0300244 if (wl->band == IEEE80211_BAND_2GHZ)
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300245 join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS |
246 CONF_HW_BIT_RATE_2MBPS |
247 CONF_HW_BIT_RATE_5_5MBPS |
248 CONF_HW_BIT_RATE_11MBPS);
Teemu Paasikivia4102642009-10-13 12:47:51 +0300249 else {
250 join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300251 join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS |
252 CONF_HW_BIT_RATE_12MBPS |
253 CONF_HW_BIT_RATE_24MBPS);
Teemu Paasikivia4102642009-10-13 12:47:51 +0300254 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300255
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300256 join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT);
Luciano Coelhoae751ba2009-10-12 15:08:57 +0300257 join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
Teemu Paasikivia4102642009-10-13 12:47:51 +0300258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300259 join->channel = wl->channel;
260 join->ssid_len = wl->ssid_len;
261 memcpy(join->ssid, wl->ssid, wl->ssid_len);
262 join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
263
264 /* increment the session counter */
265 wl->session_counter++;
266 if (wl->session_counter >= SESSION_COUNTER_MAX)
267 wl->session_counter = 0;
268
269 join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
270
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300271 /* reset TX security counters */
272 wl->tx_security_last_seq = 0;
273 wl->tx_security_seq_16 = 0;
274 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300275
276 ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
277 if (ret < 0) {
278 wl1271_error("failed to initiate cmd join");
279 goto out_free;
280 }
281
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300282 wl->joined = true;
283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300284 /*
285 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
286 * simplify locking we just sleep instead, for now
287 */
Juuso Oikarinend94cd292009-10-08 21:56:25 +0300288 msleep(10);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300289
290out_free:
291 kfree(join);
292
293out:
294 return ret;
295}
296
297/**
298 * send test command to firmware
299 *
300 * @wl: wl struct
301 * @buf: buffer containing the command, with all headers, must work with dma
302 * @len: length of the buffer
303 * @answer: is answer needed
304 */
305int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
306{
307 int ret;
308
309 wl1271_debug(DEBUG_CMD, "cmd test");
310
311 ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len);
312
313 if (ret < 0) {
314 wl1271_warning("TEST command failed");
315 return ret;
316 }
317
318 if (answer) {
319 struct wl1271_command *cmd_answer;
320
321 /*
322 * The test command got in, we can read the answer.
323 * The answer would be a wl1271_command, where the
324 * parameter array contains the actual answer.
325 */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300326 wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300327
328 cmd_answer = buf;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300329 }
330
331 return 0;
332}
333
334/**
335 * read acx from firmware
336 *
337 * @wl: wl struct
338 * @id: acx id
339 * @buf: buffer for the response, including all headers, must work with dma
340 * @len: lenght of buf
341 */
342int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
343{
344 struct acx_header *acx = buf;
345 int ret;
346
347 wl1271_debug(DEBUG_CMD, "cmd interrogate");
348
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300349 acx->id = cpu_to_le16(id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300350
351 /* payload length, does not include any headers */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300352 acx->len = cpu_to_le16(len - sizeof(*acx));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300353
354 ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
355 if (ret < 0) {
356 wl1271_error("INTERROGATE command failed");
357 goto out;
358 }
359
360 /* the interrogate command got in, we can read the answer */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300361 wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300363out:
364 return ret;
365}
366
367/**
368 * write acx value to firmware
369 *
370 * @wl: wl struct
371 * @id: acx id
372 * @buf: buffer containing acx, including all headers, must work with dma
373 * @len: length of buf
374 */
375int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
376{
377 struct acx_header *acx = buf;
378 int ret;
379
380 wl1271_debug(DEBUG_CMD, "cmd configure");
381
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300382 acx->id = cpu_to_le16(id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300383
384 /* payload length, does not include any headers */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300385 acx->len = cpu_to_le16(len - sizeof(*acx));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300386
387 ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len);
388 if (ret < 0) {
389 wl1271_warning("CONFIGURE command NOK");
390 return ret;
391 }
392
393 return 0;
394}
395
396int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
397{
398 struct cmd_enabledisable_path *cmd;
399 int ret;
400 u16 cmd_rx, cmd_tx;
401
402 wl1271_debug(DEBUG_CMD, "cmd data path");
403
404 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
405 if (!cmd) {
406 ret = -ENOMEM;
407 goto out;
408 }
409
410 cmd->channel = channel;
411
412 if (enable) {
413 cmd_rx = CMD_ENABLE_RX;
414 cmd_tx = CMD_ENABLE_TX;
415 } else {
416 cmd_rx = CMD_DISABLE_RX;
417 cmd_tx = CMD_DISABLE_TX;
418 }
419
420 ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
421 if (ret < 0) {
422 wl1271_error("rx %s cmd for channel %d failed",
423 enable ? "start" : "stop", channel);
424 goto out;
425 }
426
427 wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
428 enable ? "start" : "stop", channel);
429
430 ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
431 if (ret < 0) {
432 wl1271_error("tx %s cmd for channel %d failed",
433 enable ? "start" : "stop", channel);
434 return ret;
435 }
436
437 wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
438 enable ? "start" : "stop", channel);
439
440out:
441 kfree(cmd);
442 return ret;
443}
444
445int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
446{
447 struct wl1271_cmd_ps_params *ps_params = NULL;
448 int ret = 0;
449
450 /* FIXME: this should be in ps.c */
Juuso Oikarinen51f2be22009-10-13 12:47:42 +0300451 ret = wl1271_acx_wake_up_conditions(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300452 if (ret < 0) {
453 wl1271_error("couldn't set wake up conditions");
454 goto out;
455 }
456
457 wl1271_debug(DEBUG_CMD, "cmd set ps mode");
458
459 ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
460 if (!ps_params) {
461 ret = -ENOMEM;
462 goto out;
463 }
464
465 ps_params->ps_mode = ps_mode;
466 ps_params->send_null_data = 1;
467 ps_params->retries = 5;
468 ps_params->hang_over_period = 128;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300469 ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
471 ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
472 sizeof(*ps_params));
473 if (ret < 0) {
474 wl1271_error("cmd set_ps_mode failed");
475 goto out;
476 }
477
478out:
479 kfree(ps_params);
480 return ret;
481}
482
483int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
484 size_t len)
485{
486 struct cmd_read_write_memory *cmd;
487 int ret = 0;
488
489 wl1271_debug(DEBUG_CMD, "cmd read memory");
490
491 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
492 if (!cmd) {
493 ret = -ENOMEM;
494 goto out;
495 }
496
497 WARN_ON(len > MAX_READ_SIZE);
498 len = min_t(size_t, len, MAX_READ_SIZE);
499
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300500 cmd->addr = cpu_to_le32(addr);
501 cmd->size = cpu_to_le32(len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502
503 ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
504 if (ret < 0) {
505 wl1271_error("read memory command failed: %d", ret);
506 goto out;
507 }
508
509 /* the read command got in, we can now read the answer */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300510 wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511 memcpy(answer, cmd->value, len);
512
513out:
514 kfree(cmd);
515 return ret;
516}
517
518int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300519 u8 active_scan, u8 high_prio, u8 band,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300520 u8 probe_requests)
521{
522
523 struct wl1271_cmd_trigger_scan_to *trigger = NULL;
524 struct wl1271_cmd_scan *params = NULL;
Teemu Paasikivi311494c2009-10-13 12:47:49 +0300525 struct ieee80211_channel *channels;
526 int i, j, n_ch, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300527 u16 scan_options = 0;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300528 u8 ieee_band;
529
530 if (band == WL1271_SCAN_BAND_2_4_GHZ)
531 ieee_band = IEEE80211_BAND_2GHZ;
532 else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
533 ieee_band = IEEE80211_BAND_2GHZ;
534 else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
535 ieee_band = IEEE80211_BAND_5GHZ;
536 else
537 return -EINVAL;
538
539 if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
540 return -EINVAL;
541
542 channels = wl->hw->wiphy->bands[ieee_band]->channels;
543 n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300544
545 if (wl->scanning)
546 return -EINVAL;
547
548 params = kzalloc(sizeof(*params), GFP_KERNEL);
549 if (!params)
550 return -ENOMEM;
551
552 params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
553 params->params.rx_filter_options =
554 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
555
556 if (!active_scan)
557 scan_options |= WL1271_SCAN_OPT_PASSIVE;
558 if (high_prio)
559 scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300560 params->params.scan_options = cpu_to_le16(scan_options);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562 params->params.num_probe_requests = probe_requests;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300563 /* Let the fw autodetect suitable tx_rate for probes */
564 params->params.tx_rate = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300565 params->params.tid_trigger = 0;
566 params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
567
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300568 if (band == WL1271_SCAN_BAND_DUAL)
569 params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
570 else
571 params->params.band = band;
572
Teemu Paasikivi311494c2009-10-13 12:47:49 +0300573 for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
574 if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
575 params->channels[j].min_duration =
576 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
577 params->channels[j].max_duration =
578 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
579 memset(&params->channels[j].bssid_lsb, 0xff, 4);
580 memset(&params->channels[j].bssid_msb, 0xff, 2);
581 params->channels[j].early_termination = 0;
582 params->channels[j].tx_power_att =
583 WL1271_SCAN_CURRENT_TX_PWR;
584 params->channels[j].channel = channels[i].hw_value;
585 j++;
586 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587 }
588
Teemu Paasikivi311494c2009-10-13 12:47:49 +0300589 params->params.num_channels = j;
590
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591 if (len && ssid) {
592 params->params.ssid_len = len;
593 memcpy(params->params.ssid, ssid, len);
594 }
595
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300596 ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597 if (ret < 0) {
598 wl1271_error("PROBE request template failed");
599 goto out;
600 }
601
602 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
603 if (!trigger) {
604 ret = -ENOMEM;
605 goto out;
606 }
607
608 /* disable the timeout */
609 trigger->timeout = 0;
610
611 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
612 sizeof(*trigger));
613 if (ret < 0) {
614 wl1271_error("trigger scan to failed for hw scan");
615 goto out;
616 }
617
618 wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
619
620 wl->scanning = true;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300621 if (wl1271_11a_enabled()) {
622 wl->scan.state = band;
623 if (band == WL1271_SCAN_BAND_DUAL) {
624 wl->scan.active = active_scan;
625 wl->scan.high_prio = high_prio;
626 wl->scan.probe_requests = probe_requests;
627 if (len && ssid) {
628 wl->scan.ssid_len = len;
629 memcpy(wl->scan.ssid, ssid, len);
630 } else
631 wl->scan.ssid_len = 0;
632 }
633 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634
635 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
636 if (ret < 0) {
637 wl1271_error("SCAN failed");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638 wl->scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 goto out;
640 }
641
642out:
643 kfree(params);
644 return ret;
645}
646
647int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
648 void *buf, size_t buf_len)
649{
650 struct wl1271_cmd_template_set *cmd;
651 int ret = 0;
652
653 wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
654
655 WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
656 buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
657
658 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
659 if (!cmd) {
660 ret = -ENOMEM;
661 goto out;
662 }
663
664 cmd->len = cpu_to_le16(buf_len);
665 cmd->template_type = template_id;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300666 cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates);
Juuso Oikarinen45b531a2009-10-13 12:47:41 +0300667 cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
668 cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669
670 if (buf)
671 memcpy(cmd->template_data, buf, buf_len);
672
673 ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd));
674 if (ret < 0) {
675 wl1271_warning("cmd set_template failed: %d", ret);
676 goto out_free;
677 }
678
679out_free:
680 kfree(cmd);
681
682out:
683 return ret;
684}
685
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300686static int wl1271_build_basic_rates(char *rates, u8 band)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687{
688 u8 index = 0;
689
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300690 if (band == IEEE80211_BAND_2GHZ) {
691 rates[index++] =
692 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
693 rates[index++] =
694 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
695 rates[index++] =
696 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
697 rates[index++] =
698 IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
699 } else if (band == IEEE80211_BAND_5GHZ) {
700 rates[index++] =
701 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
702 rates[index++] =
703 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
704 rates[index++] =
705 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
706 } else {
707 wl1271_error("build_basic_rates invalid band: %d", band);
708 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
710 return index;
711}
712
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300713static int wl1271_build_extended_rates(char *rates, u8 band)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714{
715 u8 index = 0;
716
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300717 if (band == IEEE80211_BAND_2GHZ) {
718 rates[index++] = IEEE80211_OFDM_RATE_6MB;
719 rates[index++] = IEEE80211_OFDM_RATE_9MB;
720 rates[index++] = IEEE80211_OFDM_RATE_12MB;
721 rates[index++] = IEEE80211_OFDM_RATE_18MB;
722 rates[index++] = IEEE80211_OFDM_RATE_24MB;
723 rates[index++] = IEEE80211_OFDM_RATE_36MB;
724 rates[index++] = IEEE80211_OFDM_RATE_48MB;
725 rates[index++] = IEEE80211_OFDM_RATE_54MB;
726 } else if (band == IEEE80211_BAND_5GHZ) {
727 rates[index++] =
728 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
729 rates[index++] =
730 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
731 rates[index++] =
732 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
733 rates[index++] =
734 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
735 rates[index++] =
736 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
737 rates[index++] =
738 IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
739 } else {
740 wl1271_error("build_basic_rates invalid band: %d", band);
741 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300742
743 return index;
744}
745
746int wl1271_cmd_build_null_data(struct wl1271 *wl)
747{
748 struct wl12xx_null_data_template template;
749
750 if (!is_zero_ether_addr(wl->bssid)) {
751 memcpy(template.header.da, wl->bssid, ETH_ALEN);
752 memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
753 } else {
754 memset(template.header.da, 0xff, ETH_ALEN);
755 memset(template.header.bssid, 0xff, ETH_ALEN);
756 }
757
758 memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
759 template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
Juuso Oikarinen7a380792009-10-15 10:33:26 +0300760 IEEE80211_STYPE_NULLFUNC |
761 IEEE80211_FCTL_TODS);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
763 return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
764 sizeof(template));
765
766}
767
768int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
769{
770 struct wl12xx_ps_poll_template template;
771
772 memcpy(template.bssid, wl->bssid, ETH_ALEN);
773 memcpy(template.ta, wl->mac_addr, ETH_ALEN);
Juuso Oikarinenc3fea192009-10-08 21:56:22 +0300774
775 /* aid in PS-Poll has its two MSBs each set to 1 */
776 template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
779
780 return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
781 sizeof(template));
782
783}
784
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300785int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
786 u8 band)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787{
788 struct wl12xx_probe_req_template template;
789 struct wl12xx_ie_rates *rates;
790 char *ptr;
791 u16 size;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300792 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300793
794 ptr = (char *)&template;
795 size = sizeof(struct ieee80211_header);
796
797 memset(template.header.da, 0xff, ETH_ALEN);
798 memset(template.header.bssid, 0xff, ETH_ALEN);
799 memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
800 template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
801
802 /* IEs */
803 /* SSID */
804 template.ssid.header.id = WLAN_EID_SSID;
805 template.ssid.header.len = ssid_len;
806 if (ssid_len && ssid)
807 memcpy(template.ssid.ssid, ssid, ssid_len);
808 size += sizeof(struct wl12xx_ie_header) + ssid_len;
809 ptr += size;
810
811 /* Basic Rates */
812 rates = (struct wl12xx_ie_rates *)ptr;
813 rates->header.id = WLAN_EID_SUPP_RATES;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300814 rates->header.len = wl1271_build_basic_rates(rates->rates, band);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815 size += sizeof(struct wl12xx_ie_header) + rates->header.len;
816 ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
817
818 /* Extended rates */
819 rates = (struct wl12xx_ie_rates *)ptr;
820 rates->header.id = WLAN_EID_EXT_SUPP_RATES;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300821 rates->header.len = wl1271_build_extended_rates(rates->rates, band);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300822 size += sizeof(struct wl12xx_ie_header) + rates->header.len;
823
824 wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
825
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +0300826 if (band == IEEE80211_BAND_2GHZ)
827 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
828 &template, size);
829 else
830 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
831 &template, size);
832 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833}
834
835int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
836{
837 struct wl1271_cmd_set_keys *cmd;
838 int ret = 0;
839
840 wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
841
842 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
843 if (!cmd) {
844 ret = -ENOMEM;
845 goto out;
846 }
847
848 cmd->id = id;
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300849 cmd->key_action = cpu_to_le16(KEY_SET_ID);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300850 cmd->key_type = KEY_WEP;
851
852 ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
853 if (ret < 0) {
854 wl1271_warning("cmd set_default_wep_key failed: %d", ret);
855 goto out;
856 }
857
858out:
859 kfree(cmd);
860
861 return ret;
862}
863
864int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300865 u8 key_size, const u8 *key, const u8 *addr,
866 u32 tx_seq_32, u16 tx_seq_16)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867{
868 struct wl1271_cmd_set_keys *cmd;
869 int ret = 0;
870
871 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
872 if (!cmd) {
873 ret = -ENOMEM;
874 goto out;
875 }
876
877 if (key_type != KEY_WEP)
878 memcpy(cmd->addr, addr, ETH_ALEN);
879
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300880 cmd->key_action = cpu_to_le16(action);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881 cmd->key_size = key_size;
882 cmd->key_type = key_type;
883
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300884 cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
885 cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 /* we have only one SSID profile */
888 cmd->ssid_profile = 0;
889
890 cmd->id = id;
891
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892 if (key_type == KEY_TKIP) {
893 /*
894 * We get the key in the following form:
895 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
896 * but the target is expecting:
897 * TKIP - RX MIC - TX MIC
898 */
899 memcpy(cmd->key, key, 16);
900 memcpy(cmd->key + 16, key + 24, 8);
901 memcpy(cmd->key + 24, key + 16, 8);
902
903 } else {
904 memcpy(cmd->key, key, key_size);
905 }
906
907 wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
908
909 ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
910 if (ret < 0) {
911 wl1271_warning("could not set keys");
912 goto out;
913 }
914
915out:
916 kfree(cmd);
917
918 return ret;
919}
Luciano Coelho25a7dc62009-10-12 15:08:42 +0300920
921int wl1271_cmd_disconnect(struct wl1271 *wl)
922{
923 struct wl1271_cmd_disconnect *cmd;
924 int ret = 0;
925
926 wl1271_debug(DEBUG_CMD, "cmd disconnect");
927
928 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
929 if (!cmd) {
930 ret = -ENOMEM;
931 goto out;
932 }
933
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300934 cmd->rx_config_options = cpu_to_le32(wl->rx_config);
935 cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
Luciano Coelho25a7dc62009-10-12 15:08:42 +0300936 /* disconnect reason is not used in immediate disconnections */
937 cmd->type = DISCONNECT_IMMEDIATE;
938
939 ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd));
940 if (ret < 0) {
941 wl1271_error("failed to send disconnect command");
942 goto out_free;
943 }
944
945out_free:
946 kfree(cmd);
947
948out:
949 return ret;
950}