aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_cmd.c
diff options
context:
space:
mode:
authorLuciano Coelho <luciano.coelho@nokia.com>2009-08-06 09:25:28 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:12:46 -0400
commitf5fc0f86b02afef1119b523623b4cde41475bc8c (patch)
tree793be075412781fef4fcd752032e9b3680eaf96f /drivers/net/wireless/wl12xx/wl1271_cmd.c
parentb935df01ed4f0848f29b1e39c4f95d87b0206dea (diff)
wl1271: add wl1271 driver files
This driver supports the wl1271 chipset from Texas Instruments based on the WiLink(tm) 6.0 mobile platform. Support for wl1273 should be relatively easy to add. This chipset is designed for embedded devices, with good powersaving capabilities. The wl1271 chipset is the successor of wl1251 and supports the 802.11b/g/n standards, but currently this driver supports only b/g. More information about this chipset can be found here: http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?templateId=6123&navigationId=12762&contentId=29993 Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c813
1 files changed, 813 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
new file mode 100644
index 000000000000..2a4351ff54dc
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -0,0 +1,813 @@
1/*
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;
53 cmd->id = id;
54 cmd->status = 0;
55
56 WARN_ON(len % 4 != 0);
57
58 wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
59
60 wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
61
62 timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
63
64 intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
65 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
74 intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
75 }
76
77 wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
78 WL1271_ACX_INTR_CMD_COMPLETE);
79
80out:
81 return ret;
82}
83
84int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
85{
86 struct wl1271_cmd_cal_channel_tune *cmd;
87 int ret = 0;
88
89 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
90 if (!cmd)
91 return -ENOMEM;
92
93 cmd->test.id = TEST_CMD_CHANNEL_TUNE;
94
95 cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
96 /* set up any channel, 7 is in the middle of the range */
97 cmd->channel = 7;
98
99 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
100 if (ret < 0)
101 wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
102
103 kfree(cmd);
104 return ret;
105}
106
107int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
108{
109 struct wl1271_cmd_cal_update_ref_point *cmd;
110 int ret = 0;
111
112 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
113 if (!cmd)
114 return -ENOMEM;
115
116 cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
117
118 /* FIXME: still waiting for the correct values */
119 cmd->ref_power = 0;
120 cmd->ref_detector = 0;
121
122 cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G;
123
124 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
125 if (ret < 0)
126 wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
127
128 kfree(cmd);
129 return ret;
130}
131
132int wl1271_cmd_cal_p2g(struct wl1271 *wl)
133{
134 struct wl1271_cmd_cal_p2g *cmd;
135 int ret = 0;
136
137 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
138 if (!cmd)
139 return -ENOMEM;
140
141 cmd->test.id = TEST_CMD_P2G_CAL;
142
143 cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
144
145 ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
146 if (ret < 0)
147 wl1271_warning("TEST_CMD_P2G_CAL failed");
148
149 kfree(cmd);
150 return ret;
151}
152
153int wl1271_cmd_cal(struct wl1271 *wl)
154{
155 /*
156 * FIXME: we must make sure that we're not sleeping when calibration
157 * is done
158 */
159 int ret;
160
161 wl1271_notice("performing tx calibration");
162
163 ret = wl1271_cmd_cal_channel_tune(wl);
164 if (ret < 0)
165 return ret;
166
167 ret = wl1271_cmd_cal_update_ref_point(wl);
168 if (ret < 0)
169 return ret;
170
171 ret = wl1271_cmd_cal_p2g(wl);
172 if (ret < 0)
173 return ret;
174
175 return ret;
176}
177
178int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
179 u16 beacon_interval, u8 wait)
180{
181 static bool do_cal = true;
182 unsigned long timeout;
183 struct wl1271_cmd_join *join;
184 int ret, i;
185 u8 *bssid;
186
187 /* FIXME: remove when we get calibration from the factory */
188 if (do_cal) {
189 ret = wl1271_cmd_cal(wl);
190 if (ret < 0)
191 wl1271_warning("couldn't calibrate");
192 else
193 do_cal = false;
194 }
195
196
197 join = kzalloc(sizeof(*join), GFP_KERNEL);
198 if (!join) {
199 ret = -ENOMEM;
200 goto out;
201 }
202
203 wl1271_debug(DEBUG_CMD, "cmd join");
204
205 /* Reverse order BSSID */
206 bssid = (u8 *) &join->bssid_lsb;
207 for (i = 0; i < ETH_ALEN; i++)
208 bssid[i] = wl->bssid[ETH_ALEN - i - 1];
209
210 join->rx_config_options = wl->rx_config;
211 join->rx_filter_options = wl->rx_filter;
212
213 join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
214 RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
215
216 join->beacon_interval = beacon_interval;
217 join->dtim_interval = dtim_interval;
218 join->bss_type = bss_type;
219 join->channel = wl->channel;
220 join->ssid_len = wl->ssid_len;
221 memcpy(join->ssid, wl->ssid, wl->ssid_len);
222 join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
223
224 /* increment the session counter */
225 wl->session_counter++;
226 if (wl->session_counter >= SESSION_COUNTER_MAX)
227 wl->session_counter = 0;
228
229 join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
230
231
232 ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
233 if (ret < 0) {
234 wl1271_error("failed to initiate cmd join");
235 goto out_free;
236 }
237
238 timeout = msecs_to_jiffies(JOIN_TIMEOUT);
239
240 /*
241 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
242 * simplify locking we just sleep instead, for now
243 */
244 if (wait)
245 msleep(10);
246
247out_free:
248 kfree(join);
249
250out:
251 return ret;
252}
253
254/**
255 * send test command to firmware
256 *
257 * @wl: wl struct
258 * @buf: buffer containing the command, with all headers, must work with dma
259 * @len: length of the buffer
260 * @answer: is answer needed
261 */
262int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
263{
264 int ret;
265
266 wl1271_debug(DEBUG_CMD, "cmd test");
267
268 ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len);
269
270 if (ret < 0) {
271 wl1271_warning("TEST command failed");
272 return ret;
273 }
274
275 if (answer) {
276 struct wl1271_command *cmd_answer;
277
278 /*
279 * The test command got in, we can read the answer.
280 * The answer would be a wl1271_command, where the
281 * parameter array contains the actual answer.
282 */
283 wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
284
285 cmd_answer = buf;
286
287 if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
288 wl1271_error("TEST command answer error: %d",
289 cmd_answer->header.status);
290 }
291
292 return 0;
293}
294
295/**
296 * read acx from firmware
297 *
298 * @wl: wl struct
299 * @id: acx id
300 * @buf: buffer for the response, including all headers, must work with dma
301 * @len: lenght of buf
302 */
303int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
304{
305 struct acx_header *acx = buf;
306 int ret;
307
308 wl1271_debug(DEBUG_CMD, "cmd interrogate");
309
310 acx->id = id;
311
312 /* payload length, does not include any headers */
313 acx->len = len - sizeof(*acx);
314
315 ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
316 if (ret < 0) {
317 wl1271_error("INTERROGATE command failed");
318 goto out;
319 }
320
321 /* the interrogate command got in, we can read the answer */
322 wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
323
324 acx = buf;
325 if (acx->cmd.status != CMD_STATUS_SUCCESS)
326 wl1271_error("INTERROGATE command error: %d",
327 acx->cmd.status);
328
329out:
330 return ret;
331}
332
333/**
334 * write acx value to firmware
335 *
336 * @wl: wl struct
337 * @id: acx id
338 * @buf: buffer containing acx, including all headers, must work with dma
339 * @len: length of buf
340 */
341int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
342{
343 struct acx_header *acx = buf;
344 int ret;
345
346 wl1271_debug(DEBUG_CMD, "cmd configure");
347
348 acx->id = id;
349
350 /* payload length, does not include any headers */
351 acx->len = len - sizeof(*acx);
352
353 ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len);
354 if (ret < 0) {
355 wl1271_warning("CONFIGURE command NOK");
356 return ret;
357 }
358
359 return 0;
360}
361
362int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
363{
364 struct cmd_enabledisable_path *cmd;
365 int ret;
366 u16 cmd_rx, cmd_tx;
367
368 wl1271_debug(DEBUG_CMD, "cmd data path");
369
370 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
371 if (!cmd) {
372 ret = -ENOMEM;
373 goto out;
374 }
375
376 cmd->channel = channel;
377
378 if (enable) {
379 cmd_rx = CMD_ENABLE_RX;
380 cmd_tx = CMD_ENABLE_TX;
381 } else {
382 cmd_rx = CMD_DISABLE_RX;
383 cmd_tx = CMD_DISABLE_TX;
384 }
385
386 ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
387 if (ret < 0) {
388 wl1271_error("rx %s cmd for channel %d failed",
389 enable ? "start" : "stop", channel);
390 goto out;
391 }
392
393 wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
394 enable ? "start" : "stop", channel);
395
396 ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
397 if (ret < 0) {
398 wl1271_error("tx %s cmd for channel %d failed",
399 enable ? "start" : "stop", channel);
400 return ret;
401 }
402
403 wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
404 enable ? "start" : "stop", channel);
405
406out:
407 kfree(cmd);
408 return ret;
409}
410
411int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
412{
413 struct wl1271_cmd_ps_params *ps_params = NULL;
414 int ret = 0;
415
416 /* FIXME: this should be in ps.c */
417 ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
418 wl->listen_int);
419 if (ret < 0) {
420 wl1271_error("couldn't set wake up conditions");
421 goto out;
422 }
423
424 wl1271_debug(DEBUG_CMD, "cmd set ps mode");
425
426 ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
427 if (!ps_params) {
428 ret = -ENOMEM;
429 goto out;
430 }
431
432 ps_params->ps_mode = ps_mode;
433 ps_params->send_null_data = 1;
434 ps_params->retries = 5;
435 ps_params->hang_over_period = 128;
436 ps_params->null_data_rate = 1; /* 1 Mbps */
437
438 ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
439 sizeof(*ps_params));
440 if (ret < 0) {
441 wl1271_error("cmd set_ps_mode failed");
442 goto out;
443 }
444
445out:
446 kfree(ps_params);
447 return ret;
448}
449
450int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
451 size_t len)
452{
453 struct cmd_read_write_memory *cmd;
454 int ret = 0;
455
456 wl1271_debug(DEBUG_CMD, "cmd read memory");
457
458 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
459 if (!cmd) {
460 ret = -ENOMEM;
461 goto out;
462 }
463
464 WARN_ON(len > MAX_READ_SIZE);
465 len = min_t(size_t, len, MAX_READ_SIZE);
466
467 cmd->addr = addr;
468 cmd->size = len;
469
470 ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
471 if (ret < 0) {
472 wl1271_error("read memory command failed: %d", ret);
473 goto out;
474 }
475
476 /* the read command got in, we can now read the answer */
477 wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
478
479 if (cmd->header.status != CMD_STATUS_SUCCESS)
480 wl1271_error("error in read command result: %d",
481 cmd->header.status);
482
483 memcpy(answer, cmd->value, len);
484
485out:
486 kfree(cmd);
487 return ret;
488}
489
490int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
491 u8 active_scan, u8 high_prio, u8 num_channels,
492 u8 probe_requests)
493{
494
495 struct wl1271_cmd_trigger_scan_to *trigger = NULL;
496 struct wl1271_cmd_scan *params = NULL;
497 int i, ret;
498 u16 scan_options = 0;
499
500 if (wl->scanning)
501 return -EINVAL;
502
503 params = kzalloc(sizeof(*params), GFP_KERNEL);
504 if (!params)
505 return -ENOMEM;
506
507 params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
508 params->params.rx_filter_options =
509 cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
510
511 if (!active_scan)
512 scan_options |= WL1271_SCAN_OPT_PASSIVE;
513 if (high_prio)
514 scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
515 params->params.scan_options = scan_options;
516
517 params->params.num_channels = num_channels;
518 params->params.num_probe_requests = probe_requests;
519 params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS);
520 params->params.tid_trigger = 0;
521 params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
522
523 for (i = 0; i < num_channels; i++) {
524 params->channels[i].min_duration =
525 cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
526 params->channels[i].max_duration =
527 cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
528 memset(&params->channels[i].bssid_lsb, 0xff, 4);
529 memset(&params->channels[i].bssid_msb, 0xff, 2);
530 params->channels[i].early_termination = 0;
531 params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR;
532 params->channels[i].channel = i + 1;
533 }
534
535 if (len && ssid) {
536 params->params.ssid_len = len;
537 memcpy(params->params.ssid, ssid, len);
538 }
539
540 ret = wl1271_cmd_build_probe_req(wl, ssid, len);
541 if (ret < 0) {
542 wl1271_error("PROBE request template failed");
543 goto out;
544 }
545
546 trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
547 if (!trigger) {
548 ret = -ENOMEM;
549 goto out;
550 }
551
552 /* disable the timeout */
553 trigger->timeout = 0;
554
555 ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
556 sizeof(*trigger));
557 if (ret < 0) {
558 wl1271_error("trigger scan to failed for hw scan");
559 goto out;
560 }
561
562 wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
563
564 wl->scanning = true;
565
566 ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
567 if (ret < 0) {
568 wl1271_error("SCAN failed");
569 goto out;
570 }
571
572 wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
573
574 if (params->header.status != CMD_STATUS_SUCCESS) {
575 wl1271_error("Scan command error: %d",
576 params->header.status);
577 wl->scanning = false;
578 ret = -EIO;
579 goto out;
580 }
581
582out:
583 kfree(params);
584 return ret;
585}
586
587int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
588 void *buf, size_t buf_len)
589{
590 struct wl1271_cmd_template_set *cmd;
591 int ret = 0;
592
593 wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
594
595 WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
596 buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
597
598 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
599 if (!cmd) {
600 ret = -ENOMEM;
601 goto out;
602 }
603
604 cmd->len = cpu_to_le16(buf_len);
605 cmd->template_type = template_id;
606 cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
607 cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT;
608 cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT;
609
610 if (buf)
611 memcpy(cmd->template_data, buf, buf_len);
612
613 ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd));
614 if (ret < 0) {
615 wl1271_warning("cmd set_template failed: %d", ret);
616 goto out_free;
617 }
618
619out_free:
620 kfree(cmd);
621
622out:
623 return ret;
624}
625
626static int wl1271_build_basic_rates(char *rates)
627{
628 u8 index = 0;
629
630 rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
631 rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
632 rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
633 rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
634
635 return index;
636}
637
638static int wl1271_build_extended_rates(char *rates)
639{
640 u8 index = 0;
641
642 rates[index++] = IEEE80211_OFDM_RATE_6MB;
643 rates[index++] = IEEE80211_OFDM_RATE_9MB;
644 rates[index++] = IEEE80211_OFDM_RATE_12MB;
645 rates[index++] = IEEE80211_OFDM_RATE_18MB;
646 rates[index++] = IEEE80211_OFDM_RATE_24MB;
647 rates[index++] = IEEE80211_OFDM_RATE_36MB;
648 rates[index++] = IEEE80211_OFDM_RATE_48MB;
649 rates[index++] = IEEE80211_OFDM_RATE_54MB;
650
651 return index;
652}
653
654int wl1271_cmd_build_null_data(struct wl1271 *wl)
655{
656 struct wl12xx_null_data_template template;
657
658 if (!is_zero_ether_addr(wl->bssid)) {
659 memcpy(template.header.da, wl->bssid, ETH_ALEN);
660 memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
661 } else {
662 memset(template.header.da, 0xff, ETH_ALEN);
663 memset(template.header.bssid, 0xff, ETH_ALEN);
664 }
665
666 memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
667 template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
668 IEEE80211_STYPE_NULLFUNC);
669
670 return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
671 sizeof(template));
672
673}
674
675int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
676{
677 struct wl12xx_ps_poll_template template;
678
679 memcpy(template.bssid, wl->bssid, ETH_ALEN);
680 memcpy(template.ta, wl->mac_addr, ETH_ALEN);
681 template.aid = aid;
682 template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
683
684 return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
685 sizeof(template));
686
687}
688
689int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
690{
691 struct wl12xx_probe_req_template template;
692 struct wl12xx_ie_rates *rates;
693 char *ptr;
694 u16 size;
695
696 ptr = (char *)&template;
697 size = sizeof(struct ieee80211_header);
698
699 memset(template.header.da, 0xff, ETH_ALEN);
700 memset(template.header.bssid, 0xff, ETH_ALEN);
701 memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
702 template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
703
704 /* IEs */
705 /* SSID */
706 template.ssid.header.id = WLAN_EID_SSID;
707 template.ssid.header.len = ssid_len;
708 if (ssid_len && ssid)
709 memcpy(template.ssid.ssid, ssid, ssid_len);
710 size += sizeof(struct wl12xx_ie_header) + ssid_len;
711 ptr += size;
712
713 /* Basic Rates */
714 rates = (struct wl12xx_ie_rates *)ptr;
715 rates->header.id = WLAN_EID_SUPP_RATES;
716 rates->header.len = wl1271_build_basic_rates(rates->rates);
717 size += sizeof(struct wl12xx_ie_header) + rates->header.len;
718 ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
719
720 /* Extended rates */
721 rates = (struct wl12xx_ie_rates *)ptr;
722 rates->header.id = WLAN_EID_EXT_SUPP_RATES;
723 rates->header.len = wl1271_build_extended_rates(rates->rates);
724 size += sizeof(struct wl12xx_ie_header) + rates->header.len;
725
726 wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
727
728 return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
729 &template, size);
730}
731
732int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
733{
734 struct wl1271_cmd_set_keys *cmd;
735 int ret = 0;
736
737 wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
738
739 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
740 if (!cmd) {
741 ret = -ENOMEM;
742 goto out;
743 }
744
745 cmd->id = id;
746 cmd->key_action = KEY_SET_ID;
747 cmd->key_type = KEY_WEP;
748
749 ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
750 if (ret < 0) {
751 wl1271_warning("cmd set_default_wep_key failed: %d", ret);
752 goto out;
753 }
754
755out:
756 kfree(cmd);
757
758 return ret;
759}
760
761int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
762 u8 key_size, const u8 *key, const u8 *addr)
763{
764 struct wl1271_cmd_set_keys *cmd;
765 int ret = 0;
766
767 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
768 if (!cmd) {
769 ret = -ENOMEM;
770 goto out;
771 }
772
773 if (key_type != KEY_WEP)
774 memcpy(cmd->addr, addr, ETH_ALEN);
775
776 cmd->key_action = action;
777 cmd->key_size = key_size;
778 cmd->key_type = key_type;
779
780 /* we have only one SSID profile */
781 cmd->ssid_profile = 0;
782
783 cmd->id = id;
784
785 /* FIXME: this is from wl1251, needs to be checked */
786 if (key_type == KEY_TKIP) {
787 /*
788 * We get the key in the following form:
789 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
790 * but the target is expecting:
791 * TKIP - RX MIC - TX MIC
792 */
793 memcpy(cmd->key, key, 16);
794 memcpy(cmd->key + 16, key + 24, 8);
795 memcpy(cmd->key + 24, key + 16, 8);
796
797 } else {
798 memcpy(cmd->key, key, key_size);
799 }
800
801 wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
802
803 ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
804 if (ret < 0) {
805 wl1271_warning("could not set keys");
806 goto out;
807 }
808
809out:
810 kfree(cmd);
811
812 return ret;
813}