diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1251_main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 1442 |
1 files changed, 1442 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c new file mode 100644 index 000000000000..16cd46c7164b --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -0,0 +1,1442 @@ | |||
1 | /* | ||
2 | * This file is part of wl12xx | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@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/interrupt.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/spi/spi.h> | ||
30 | #include <linux/crc32.h> | ||
31 | #include <linux/etherdevice.h> | ||
32 | #include <linux/spi/wl12xx.h> | ||
33 | |||
34 | #include "wl12xx.h" | ||
35 | #include "wl12xx_80211.h" | ||
36 | #include "reg.h" | ||
37 | #include "wl1251_ops.h" | ||
38 | #include "wl1251_spi.h" | ||
39 | #include "wl1251_event.h" | ||
40 | #include "wl1251_tx.h" | ||
41 | #include "wl1251_rx.h" | ||
42 | #include "wl1251_ps.h" | ||
43 | #include "wl1251_init.h" | ||
44 | #include "wl1251_debugfs.h" | ||
45 | |||
46 | static void wl12xx_disable_interrupts(struct wl12xx *wl) | ||
47 | { | ||
48 | disable_irq(wl->irq); | ||
49 | } | ||
50 | |||
51 | static void wl12xx_power_off(struct wl12xx *wl) | ||
52 | { | ||
53 | wl->set_power(false); | ||
54 | } | ||
55 | |||
56 | static void wl12xx_power_on(struct wl12xx *wl) | ||
57 | { | ||
58 | wl->set_power(true); | ||
59 | } | ||
60 | |||
61 | static irqreturn_t wl12xx_irq(int irq, void *cookie) | ||
62 | { | ||
63 | struct wl12xx *wl; | ||
64 | |||
65 | wl12xx_debug(DEBUG_IRQ, "IRQ"); | ||
66 | |||
67 | wl = cookie; | ||
68 | |||
69 | schedule_work(&wl->irq_work); | ||
70 | |||
71 | return IRQ_HANDLED; | ||
72 | } | ||
73 | |||
74 | static int wl12xx_fetch_firmware(struct wl12xx *wl) | ||
75 | { | ||
76 | const struct firmware *fw; | ||
77 | int ret; | ||
78 | |||
79 | ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); | ||
80 | |||
81 | if (ret < 0) { | ||
82 | wl12xx_error("could not get firmware: %d", ret); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | if (fw->size % 4) { | ||
87 | wl12xx_error("firmware size is not multiple of 32 bits: %zu", | ||
88 | fw->size); | ||
89 | ret = -EILSEQ; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | wl->fw_len = fw->size; | ||
94 | wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); | ||
95 | |||
96 | if (!wl->fw) { | ||
97 | wl12xx_error("could not allocate memory for the firmware"); | ||
98 | ret = -ENOMEM; | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
103 | |||
104 | ret = 0; | ||
105 | |||
106 | out: | ||
107 | release_firmware(fw); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int wl12xx_fetch_nvs(struct wl12xx *wl) | ||
113 | { | ||
114 | const struct firmware *fw; | ||
115 | int ret; | ||
116 | |||
117 | ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); | ||
118 | |||
119 | if (ret < 0) { | ||
120 | wl12xx_error("could not get nvs file: %d", ret); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | if (fw->size % 4) { | ||
125 | wl12xx_error("nvs size is not multiple of 32 bits: %zu", | ||
126 | fw->size); | ||
127 | ret = -EILSEQ; | ||
128 | goto out; | ||
129 | } | ||
130 | |||
131 | wl->nvs_len = fw->size; | ||
132 | wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); | ||
133 | |||
134 | if (!wl->nvs) { | ||
135 | wl12xx_error("could not allocate memory for the nvs file"); | ||
136 | ret = -ENOMEM; | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | memcpy(wl->nvs, fw->data, wl->nvs_len); | ||
141 | |||
142 | ret = 0; | ||
143 | |||
144 | out: | ||
145 | release_firmware(fw); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static void wl12xx_fw_wakeup(struct wl12xx *wl) | ||
151 | { | ||
152 | u32 elp_reg; | ||
153 | |||
154 | elp_reg = ELPCTRL_WAKE_UP; | ||
155 | wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
156 | elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
157 | |||
158 | if (!(elp_reg & ELPCTRL_WLAN_READY)) { | ||
159 | wl12xx_warning("WLAN not ready"); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static int wl12xx_chip_wakeup(struct wl12xx *wl) | ||
164 | { | ||
165 | int ret = 0; | ||
166 | |||
167 | wl12xx_power_on(wl); | ||
168 | msleep(wl->chip.power_on_sleep); | ||
169 | wl12xx_spi_reset(wl); | ||
170 | wl12xx_spi_init(wl); | ||
171 | |||
172 | /* We don't need a real memory partition here, because we only want | ||
173 | * to use the registers at this point. */ | ||
174 | wl12xx_set_partition(wl, | ||
175 | 0x00000000, | ||
176 | 0x00000000, | ||
177 | REGISTERS_BASE, | ||
178 | REGISTERS_DOWN_SIZE); | ||
179 | |||
180 | /* ELP module wake up */ | ||
181 | wl12xx_fw_wakeup(wl); | ||
182 | |||
183 | /* whal_FwCtrl_BootSm() */ | ||
184 | |||
185 | /* 0. read chip id from CHIP_ID */ | ||
186 | wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); | ||
187 | |||
188 | /* 1. check if chip id is valid */ | ||
189 | |||
190 | switch (wl->chip.id) { | ||
191 | case CHIP_ID_1251_PG12: | ||
192 | wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", | ||
193 | wl->chip.id); | ||
194 | |||
195 | wl1251_setup(wl); | ||
196 | |||
197 | break; | ||
198 | case CHIP_ID_1251_PG10: | ||
199 | case CHIP_ID_1251_PG11: | ||
200 | default: | ||
201 | wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); | ||
202 | ret = -ENODEV; | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | if (wl->fw == NULL) { | ||
207 | ret = wl12xx_fetch_firmware(wl); | ||
208 | if (ret < 0) | ||
209 | goto out; | ||
210 | } | ||
211 | |||
212 | /* No NVS from netlink, try to get it from the filesystem */ | ||
213 | if (wl->nvs == NULL) { | ||
214 | ret = wl12xx_fetch_nvs(wl); | ||
215 | if (ret < 0) | ||
216 | goto out; | ||
217 | } | ||
218 | |||
219 | out: | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static void wl12xx_filter_work(struct work_struct *work) | ||
224 | { | ||
225 | struct wl12xx *wl = | ||
226 | container_of(work, struct wl12xx, filter_work); | ||
227 | int ret; | ||
228 | |||
229 | mutex_lock(&wl->mutex); | ||
230 | |||
231 | if (wl->state == WL12XX_STATE_OFF) | ||
232 | goto out; | ||
233 | |||
234 | ret = wl12xx_ps_elp_wakeup(wl); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | /* FIXME: replace the magic numbers with proper definitions */ | ||
239 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
240 | if (ret < 0) | ||
241 | goto out_sleep; | ||
242 | |||
243 | out_sleep: | ||
244 | wl12xx_ps_elp_sleep(wl); | ||
245 | |||
246 | out: | ||
247 | mutex_unlock(&wl->mutex); | ||
248 | } | ||
249 | |||
250 | int wl12xx_plt_start(struct wl12xx *wl) | ||
251 | { | ||
252 | int ret; | ||
253 | |||
254 | wl12xx_notice("power up"); | ||
255 | |||
256 | if (wl->state != WL12XX_STATE_OFF) { | ||
257 | wl12xx_error("cannot go into PLT state because not " | ||
258 | "in off state: %d", wl->state); | ||
259 | return -EBUSY; | ||
260 | } | ||
261 | |||
262 | wl->state = WL12XX_STATE_PLT; | ||
263 | |||
264 | ret = wl12xx_chip_wakeup(wl); | ||
265 | if (ret < 0) | ||
266 | return ret; | ||
267 | |||
268 | ret = wl->chip.op_boot(wl); | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | |||
272 | wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); | ||
273 | |||
274 | ret = wl->chip.op_plt_init(wl); | ||
275 | if (ret < 0) | ||
276 | return ret; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | int wl12xx_plt_stop(struct wl12xx *wl) | ||
282 | { | ||
283 | wl12xx_notice("power down"); | ||
284 | |||
285 | if (wl->state != WL12XX_STATE_PLT) { | ||
286 | wl12xx_error("cannot power down because not in PLT " | ||
287 | "state: %d", wl->state); | ||
288 | return -EBUSY; | ||
289 | } | ||
290 | |||
291 | wl12xx_disable_interrupts(wl); | ||
292 | wl12xx_power_off(wl); | ||
293 | |||
294 | wl->state = WL12XX_STATE_OFF; | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | |||
300 | static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
301 | { | ||
302 | struct wl12xx *wl = hw->priv; | ||
303 | |||
304 | skb_queue_tail(&wl->tx_queue, skb); | ||
305 | |||
306 | /* | ||
307 | * The chip specific setup must run before the first TX packet - | ||
308 | * before that, the tx_work will not be initialized! | ||
309 | */ | ||
310 | |||
311 | schedule_work(&wl->tx_work); | ||
312 | |||
313 | /* | ||
314 | * The workqueue is slow to process the tx_queue and we need stop | ||
315 | * the queue here, otherwise the queue will get too long. | ||
316 | */ | ||
317 | if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { | ||
318 | ieee80211_stop_queues(wl->hw); | ||
319 | |||
320 | /* | ||
321 | * FIXME: this is racy, the variable is not properly | ||
322 | * protected. Maybe fix this by removing the stupid | ||
323 | * variable altogether and checking the real queue state? | ||
324 | */ | ||
325 | wl->tx_queue_stopped = true; | ||
326 | } | ||
327 | |||
328 | return NETDEV_TX_OK; | ||
329 | } | ||
330 | |||
331 | static int wl12xx_op_start(struct ieee80211_hw *hw) | ||
332 | { | ||
333 | struct wl12xx *wl = hw->priv; | ||
334 | int ret = 0; | ||
335 | |||
336 | wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); | ||
337 | |||
338 | mutex_lock(&wl->mutex); | ||
339 | |||
340 | if (wl->state != WL12XX_STATE_OFF) { | ||
341 | wl12xx_error("cannot start because not in off state: %d", | ||
342 | wl->state); | ||
343 | ret = -EBUSY; | ||
344 | goto out; | ||
345 | } | ||
346 | |||
347 | ret = wl12xx_chip_wakeup(wl); | ||
348 | if (ret < 0) | ||
349 | return ret; | ||
350 | |||
351 | ret = wl->chip.op_boot(wl); | ||
352 | if (ret < 0) | ||
353 | goto out; | ||
354 | |||
355 | ret = wl->chip.op_hw_init(wl); | ||
356 | if (ret < 0) | ||
357 | goto out; | ||
358 | |||
359 | ret = wl12xx_acx_station_id(wl); | ||
360 | if (ret < 0) | ||
361 | goto out; | ||
362 | |||
363 | wl->state = WL12XX_STATE_ON; | ||
364 | |||
365 | wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); | ||
366 | |||
367 | out: | ||
368 | if (ret < 0) | ||
369 | wl12xx_power_off(wl); | ||
370 | |||
371 | mutex_unlock(&wl->mutex); | ||
372 | |||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | static void wl12xx_op_stop(struct ieee80211_hw *hw) | ||
377 | { | ||
378 | struct wl12xx *wl = hw->priv; | ||
379 | |||
380 | wl12xx_info("down"); | ||
381 | |||
382 | wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
383 | |||
384 | mutex_lock(&wl->mutex); | ||
385 | |||
386 | WARN_ON(wl->state != WL12XX_STATE_ON); | ||
387 | |||
388 | if (wl->scanning) { | ||
389 | mutex_unlock(&wl->mutex); | ||
390 | ieee80211_scan_completed(wl->hw, true); | ||
391 | mutex_lock(&wl->mutex); | ||
392 | wl->scanning = false; | ||
393 | } | ||
394 | |||
395 | wl->state = WL12XX_STATE_OFF; | ||
396 | |||
397 | wl12xx_disable_interrupts(wl); | ||
398 | |||
399 | mutex_unlock(&wl->mutex); | ||
400 | |||
401 | cancel_work_sync(&wl->irq_work); | ||
402 | cancel_work_sync(&wl->tx_work); | ||
403 | cancel_work_sync(&wl->filter_work); | ||
404 | |||
405 | mutex_lock(&wl->mutex); | ||
406 | |||
407 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
408 | wl->chip.op_tx_flush(wl); | ||
409 | wl12xx_power_off(wl); | ||
410 | |||
411 | memset(wl->bssid, 0, ETH_ALEN); | ||
412 | wl->listen_int = 1; | ||
413 | wl->bss_type = MAX_BSS_TYPE; | ||
414 | |||
415 | wl->data_in_count = 0; | ||
416 | wl->rx_counter = 0; | ||
417 | wl->rx_handled = 0; | ||
418 | wl->rx_current_buffer = 0; | ||
419 | wl->rx_last_id = 0; | ||
420 | wl->next_tx_complete = 0; | ||
421 | wl->elp = false; | ||
422 | wl->psm = 0; | ||
423 | wl->tx_queue_stopped = false; | ||
424 | wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; | ||
425 | |||
426 | wl12xx_debugfs_reset(wl); | ||
427 | |||
428 | mutex_unlock(&wl->mutex); | ||
429 | } | ||
430 | |||
431 | static int wl12xx_op_add_interface(struct ieee80211_hw *hw, | ||
432 | struct ieee80211_if_init_conf *conf) | ||
433 | { | ||
434 | struct wl12xx *wl = hw->priv; | ||
435 | DECLARE_MAC_BUF(mac); | ||
436 | int ret = 0; | ||
437 | |||
438 | wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", | ||
439 | conf->type, print_mac(mac, conf->mac_addr)); | ||
440 | |||
441 | mutex_lock(&wl->mutex); | ||
442 | |||
443 | switch (conf->type) { | ||
444 | case NL80211_IFTYPE_STATION: | ||
445 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
446 | break; | ||
447 | case NL80211_IFTYPE_ADHOC: | ||
448 | wl->bss_type = BSS_TYPE_IBSS; | ||
449 | break; | ||
450 | default: | ||
451 | ret = -EOPNOTSUPP; | ||
452 | goto out; | ||
453 | } | ||
454 | |||
455 | if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { | ||
456 | memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | ||
457 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
458 | ret = wl12xx_acx_station_id(wl); | ||
459 | if (ret < 0) | ||
460 | goto out; | ||
461 | } | ||
462 | |||
463 | out: | ||
464 | mutex_unlock(&wl->mutex); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, | ||
469 | struct ieee80211_if_init_conf *conf) | ||
470 | { | ||
471 | wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
472 | } | ||
473 | |||
474 | static int wl12xx_build_null_data(struct wl12xx *wl) | ||
475 | { | ||
476 | struct wl12xx_null_data_template template; | ||
477 | |||
478 | if (!is_zero_ether_addr(wl->bssid)) { | ||
479 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
480 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
481 | } else { | ||
482 | memset(template.header.da, 0xff, ETH_ALEN); | ||
483 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
484 | } | ||
485 | |||
486 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
487 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
488 | IEEE80211_STYPE_NULLFUNC); | ||
489 | |||
490 | return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, | ||
491 | sizeof(template)); | ||
492 | |||
493 | } | ||
494 | |||
495 | static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) | ||
496 | { | ||
497 | struct wl12xx_ps_poll_template template; | ||
498 | |||
499 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | ||
500 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | ||
501 | template.aid = aid; | ||
502 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | ||
503 | |||
504 | return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, | ||
505 | sizeof(template)); | ||
506 | |||
507 | } | ||
508 | |||
509 | static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) | ||
510 | { | ||
511 | struct wl12xx *wl = hw->priv; | ||
512 | struct ieee80211_conf *conf = &hw->conf; | ||
513 | int channel, ret = 0; | ||
514 | |||
515 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
516 | |||
517 | wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||
518 | channel, | ||
519 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
520 | conf->power_level); | ||
521 | |||
522 | mutex_lock(&wl->mutex); | ||
523 | |||
524 | ret = wl12xx_ps_elp_wakeup(wl); | ||
525 | if (ret < 0) | ||
526 | goto out; | ||
527 | |||
528 | if (channel != wl->channel) { | ||
529 | /* FIXME: use beacon interval provided by mac80211 */ | ||
530 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
531 | if (ret < 0) | ||
532 | goto out_sleep; | ||
533 | |||
534 | wl->channel = channel; | ||
535 | } | ||
536 | |||
537 | ret = wl12xx_build_null_data(wl); | ||
538 | if (ret < 0) | ||
539 | goto out_sleep; | ||
540 | |||
541 | if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||
542 | wl12xx_info("psm enabled"); | ||
543 | |||
544 | wl->psm_requested = true; | ||
545 | |||
546 | /* | ||
547 | * We enter PSM only if we're already associated. | ||
548 | * If we're not, we'll enter it when joining an SSID, | ||
549 | * through the bss_info_changed() hook. | ||
550 | */ | ||
551 | ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
552 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
553 | wl->psm_requested) { | ||
554 | wl12xx_info("psm disabled"); | ||
555 | |||
556 | wl->psm_requested = false; | ||
557 | |||
558 | if (wl->psm) | ||
559 | ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
560 | } | ||
561 | |||
562 | if (conf->power_level != wl->power_level) { | ||
563 | ret = wl12xx_acx_tx_power(wl, conf->power_level); | ||
564 | if (ret < 0) | ||
565 | goto out; | ||
566 | |||
567 | wl->power_level = conf->power_level; | ||
568 | } | ||
569 | |||
570 | out_sleep: | ||
571 | wl12xx_ps_elp_sleep(wl); | ||
572 | |||
573 | out: | ||
574 | mutex_unlock(&wl->mutex); | ||
575 | |||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | #define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
580 | FIF_ALLMULTI | \ | ||
581 | FIF_FCSFAIL | \ | ||
582 | FIF_BCN_PRBRESP_PROMISC | \ | ||
583 | FIF_CONTROL | \ | ||
584 | FIF_OTHER_BSS) | ||
585 | |||
586 | static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, | ||
587 | unsigned int changed, | ||
588 | unsigned int *total, | ||
589 | int mc_count, | ||
590 | struct dev_addr_list *mc_list) | ||
591 | { | ||
592 | struct wl12xx *wl = hw->priv; | ||
593 | |||
594 | wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); | ||
595 | |||
596 | *total &= WL12XX_SUPPORTED_FILTERS; | ||
597 | changed &= WL12XX_SUPPORTED_FILTERS; | ||
598 | |||
599 | if (changed == 0) | ||
600 | /* no filters which we support changed */ | ||
601 | return; | ||
602 | |||
603 | /* FIXME: wl->rx_config and wl->rx_filter are not protected */ | ||
604 | |||
605 | wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; | ||
606 | wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; | ||
607 | |||
608 | if (*total & FIF_PROMISC_IN_BSS) { | ||
609 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
610 | wl->rx_config |= CFG_RX_ALL_GOOD; | ||
611 | } | ||
612 | if (*total & FIF_ALLMULTI) | ||
613 | /* | ||
614 | * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive | ||
615 | * all multicast frames | ||
616 | */ | ||
617 | wl->rx_config &= ~CFG_MC_FILTER_EN; | ||
618 | if (*total & FIF_FCSFAIL) | ||
619 | wl->rx_filter |= CFG_RX_FCS_ERROR; | ||
620 | if (*total & FIF_BCN_PRBRESP_PROMISC) { | ||
621 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||
622 | wl->rx_config &= ~CFG_SSID_FILTER_EN; | ||
623 | } | ||
624 | if (*total & FIF_CONTROL) | ||
625 | wl->rx_filter |= CFG_RX_CTL_EN; | ||
626 | if (*total & FIF_OTHER_BSS) | ||
627 | wl->rx_filter &= ~CFG_BSSID_FILTER_EN; | ||
628 | |||
629 | /* | ||
630 | * FIXME: workqueues need to be properly cancelled on stop(), for | ||
631 | * now let's just disable changing the filter settings. They will | ||
632 | * be updated any on config(). | ||
633 | */ | ||
634 | /* schedule_work(&wl->filter_work); */ | ||
635 | } | ||
636 | |||
637 | /* HW encryption */ | ||
638 | static int wl12xx_set_key_type(struct wl12xx *wl, | ||
639 | struct wl12xx_cmd_set_keys *key, | ||
640 | enum set_key_cmd cmd, | ||
641 | struct ieee80211_key_conf *mac80211_key, | ||
642 | const u8 *addr) | ||
643 | { | ||
644 | switch (mac80211_key->alg) { | ||
645 | case ALG_WEP: | ||
646 | if (is_broadcast_ether_addr(addr)) | ||
647 | key->key_type = KEY_WEP_DEFAULT; | ||
648 | else | ||
649 | key->key_type = KEY_WEP_ADDR; | ||
650 | |||
651 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
652 | break; | ||
653 | case ALG_TKIP: | ||
654 | if (is_broadcast_ether_addr(addr)) | ||
655 | key->key_type = KEY_TKIP_MIC_GROUP; | ||
656 | else | ||
657 | key->key_type = KEY_TKIP_MIC_PAIRWISE; | ||
658 | |||
659 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
660 | break; | ||
661 | case ALG_CCMP: | ||
662 | if (is_broadcast_ether_addr(addr)) | ||
663 | key->key_type = KEY_AES_GROUP; | ||
664 | else | ||
665 | key->key_type = KEY_AES_PAIRWISE; | ||
666 | mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
667 | break; | ||
668 | default: | ||
669 | wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); | ||
670 | return -EOPNOTSUPP; | ||
671 | } | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
677 | struct ieee80211_vif *vif, | ||
678 | struct ieee80211_sta *sta, | ||
679 | struct ieee80211_key_conf *key) | ||
680 | { | ||
681 | struct wl12xx *wl = hw->priv; | ||
682 | struct wl12xx_cmd_set_keys *wl_cmd; | ||
683 | const u8 *addr; | ||
684 | int ret; | ||
685 | |||
686 | static const u8 bcast_addr[ETH_ALEN] = | ||
687 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
688 | |||
689 | wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
690 | |||
691 | wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); | ||
692 | if (!wl_cmd) { | ||
693 | ret = -ENOMEM; | ||
694 | goto out; | ||
695 | } | ||
696 | |||
697 | addr = sta ? sta->addr : bcast_addr; | ||
698 | |||
699 | wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); | ||
700 | wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); | ||
701 | wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
702 | key->alg, key->keyidx, key->keylen, key->flags); | ||
703 | wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); | ||
704 | |||
705 | if (is_zero_ether_addr(addr)) { | ||
706 | /* We dont support TX only encryption */ | ||
707 | ret = -EOPNOTSUPP; | ||
708 | goto out; | ||
709 | } | ||
710 | |||
711 | mutex_lock(&wl->mutex); | ||
712 | |||
713 | ret = wl12xx_ps_elp_wakeup(wl); | ||
714 | if (ret < 0) | ||
715 | goto out_unlock; | ||
716 | |||
717 | switch (cmd) { | ||
718 | case SET_KEY: | ||
719 | wl_cmd->key_action = KEY_ADD_OR_REPLACE; | ||
720 | break; | ||
721 | case DISABLE_KEY: | ||
722 | wl_cmd->key_action = KEY_REMOVE; | ||
723 | break; | ||
724 | default: | ||
725 | wl12xx_error("Unsupported key cmd 0x%x", cmd); | ||
726 | break; | ||
727 | } | ||
728 | |||
729 | ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); | ||
730 | if (ret < 0) { | ||
731 | wl12xx_error("Set KEY type failed"); | ||
732 | goto out_sleep; | ||
733 | } | ||
734 | |||
735 | if (wl_cmd->key_type != KEY_WEP_DEFAULT) | ||
736 | memcpy(wl_cmd->addr, addr, ETH_ALEN); | ||
737 | |||
738 | if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || | ||
739 | (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { | ||
740 | /* | ||
741 | * We get the key in the following form: | ||
742 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
743 | * but the target is expecting: | ||
744 | * TKIP - RX MIC - TX MIC | ||
745 | */ | ||
746 | memcpy(wl_cmd->key, key->key, 16); | ||
747 | memcpy(wl_cmd->key + 16, key->key + 24, 8); | ||
748 | memcpy(wl_cmd->key + 24, key->key + 16, 8); | ||
749 | |||
750 | } else { | ||
751 | memcpy(wl_cmd->key, key->key, key->keylen); | ||
752 | } | ||
753 | wl_cmd->key_size = key->keylen; | ||
754 | |||
755 | wl_cmd->id = key->keyidx; | ||
756 | wl_cmd->ssid_profile = 0; | ||
757 | |||
758 | wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); | ||
759 | |||
760 | ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); | ||
761 | if (ret < 0) { | ||
762 | wl12xx_warning("could not set keys"); | ||
763 | goto out_sleep; | ||
764 | } | ||
765 | |||
766 | out_sleep: | ||
767 | wl12xx_ps_elp_sleep(wl); | ||
768 | |||
769 | out_unlock: | ||
770 | mutex_unlock(&wl->mutex); | ||
771 | |||
772 | out: | ||
773 | kfree(wl_cmd); | ||
774 | |||
775 | return ret; | ||
776 | } | ||
777 | |||
778 | static int wl12xx_build_basic_rates(char *rates) | ||
779 | { | ||
780 | u8 index = 0; | ||
781 | |||
782 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
783 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
784 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
785 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
786 | |||
787 | return index; | ||
788 | } | ||
789 | |||
790 | static int wl12xx_build_extended_rates(char *rates) | ||
791 | { | ||
792 | u8 index = 0; | ||
793 | |||
794 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | ||
795 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | ||
796 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | ||
797 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
798 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
799 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
800 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
801 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
802 | |||
803 | return index; | ||
804 | } | ||
805 | |||
806 | |||
807 | static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) | ||
808 | { | ||
809 | struct wl12xx_probe_req_template template; | ||
810 | struct wl12xx_ie_rates *rates; | ||
811 | char *ptr; | ||
812 | u16 size; | ||
813 | |||
814 | ptr = (char *)&template; | ||
815 | size = sizeof(struct ieee80211_header); | ||
816 | |||
817 | memset(template.header.da, 0xff, ETH_ALEN); | ||
818 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
819 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
820 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
821 | |||
822 | /* IEs */ | ||
823 | /* SSID */ | ||
824 | template.ssid.header.id = WLAN_EID_SSID; | ||
825 | template.ssid.header.len = ssid_len; | ||
826 | if (ssid_len && ssid) | ||
827 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
828 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
829 | ptr += size; | ||
830 | |||
831 | /* Basic Rates */ | ||
832 | rates = (struct wl12xx_ie_rates *)ptr; | ||
833 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
834 | rates->header.len = wl12xx_build_basic_rates(rates->rates); | ||
835 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
836 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
837 | |||
838 | /* Extended rates */ | ||
839 | rates = (struct wl12xx_ie_rates *)ptr; | ||
840 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
841 | rates->header.len = wl12xx_build_extended_rates(rates->rates); | ||
842 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
843 | |||
844 | wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
845 | |||
846 | return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, | ||
847 | size); | ||
848 | } | ||
849 | |||
850 | static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, | ||
851 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
852 | u8 probe_requests) | ||
853 | { | ||
854 | struct wl12xx_cmd_trigger_scan_to *trigger = NULL; | ||
855 | struct cmd_scan *params = NULL; | ||
856 | int i, ret; | ||
857 | u16 scan_options = 0; | ||
858 | |||
859 | if (wl->scanning) | ||
860 | return -EINVAL; | ||
861 | |||
862 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
863 | if (!params) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
867 | params->params.rx_filter_options = | ||
868 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
869 | |||
870 | /* High priority scan */ | ||
871 | if (!active_scan) | ||
872 | scan_options |= SCAN_PASSIVE; | ||
873 | if (high_prio) | ||
874 | scan_options |= SCAN_PRIORITY_HIGH; | ||
875 | params->params.scan_options = scan_options; | ||
876 | |||
877 | params->params.num_channels = num_channels; | ||
878 | params->params.num_probe_requests = probe_requests; | ||
879 | params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
880 | params->params.tid_trigger = 0; | ||
881 | |||
882 | for (i = 0; i < num_channels; i++) { | ||
883 | params->channels[i].min_duration = cpu_to_le32(30000); | ||
884 | params->channels[i].max_duration = cpu_to_le32(60000); | ||
885 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
886 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
887 | params->channels[i].early_termination = 0; | ||
888 | params->channels[i].tx_power_att = 0; | ||
889 | params->channels[i].channel = i + 1; | ||
890 | memset(params->channels[i].pad, 0, 3); | ||
891 | } | ||
892 | |||
893 | for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) | ||
894 | memset(¶ms->channels[i], 0, | ||
895 | sizeof(struct basic_scan_channel_parameters)); | ||
896 | |||
897 | if (len && ssid) { | ||
898 | params->params.ssid_len = len; | ||
899 | memcpy(params->params.ssid, ssid, len); | ||
900 | } else { | ||
901 | params->params.ssid_len = 0; | ||
902 | memset(params->params.ssid, 0, 32); | ||
903 | } | ||
904 | |||
905 | ret = wl12xx_build_probe_req(wl, ssid, len); | ||
906 | if (ret < 0) { | ||
907 | wl12xx_error("PROBE request template failed"); | ||
908 | goto out; | ||
909 | } | ||
910 | |||
911 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
912 | if (!trigger) | ||
913 | goto out; | ||
914 | |||
915 | trigger->timeout = 0; | ||
916 | |||
917 | ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
918 | sizeof(*trigger)); | ||
919 | if (ret < 0) { | ||
920 | wl12xx_error("trigger scan to failed for hw scan"); | ||
921 | goto out; | ||
922 | } | ||
923 | |||
924 | wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | ||
925 | |||
926 | wl->scanning = true; | ||
927 | |||
928 | ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | ||
929 | if (ret < 0) | ||
930 | wl12xx_error("SCAN failed"); | ||
931 | |||
932 | wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | ||
933 | |||
934 | if (params->header.status != CMD_STATUS_SUCCESS) { | ||
935 | wl12xx_error("TEST command answer error: %d", | ||
936 | params->header.status); | ||
937 | wl->scanning = false; | ||
938 | ret = -EIO; | ||
939 | goto out; | ||
940 | } | ||
941 | |||
942 | out: | ||
943 | kfree(params); | ||
944 | return ret; | ||
945 | |||
946 | } | ||
947 | |||
948 | static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, | ||
949 | struct cfg80211_scan_request *req) | ||
950 | { | ||
951 | struct wl12xx *wl = hw->priv; | ||
952 | int ret; | ||
953 | u8 *ssid = NULL; | ||
954 | size_t ssid_len = 0; | ||
955 | |||
956 | wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
957 | |||
958 | if (req->n_ssids) { | ||
959 | ssid = req->ssids[0].ssid; | ||
960 | ssid_len = req->ssids[0].ssid_len; | ||
961 | } | ||
962 | |||
963 | mutex_lock(&wl->mutex); | ||
964 | |||
965 | ret = wl12xx_ps_elp_wakeup(wl); | ||
966 | if (ret < 0) | ||
967 | goto out; | ||
968 | |||
969 | ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | ||
970 | |||
971 | wl12xx_ps_elp_sleep(wl); | ||
972 | |||
973 | out: | ||
974 | mutex_unlock(&wl->mutex); | ||
975 | |||
976 | return ret; | ||
977 | } | ||
978 | |||
979 | static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
980 | { | ||
981 | struct wl12xx *wl = hw->priv; | ||
982 | int ret; | ||
983 | |||
984 | mutex_lock(&wl->mutex); | ||
985 | |||
986 | ret = wl12xx_ps_elp_wakeup(wl); | ||
987 | if (ret < 0) | ||
988 | goto out; | ||
989 | |||
990 | ret = wl12xx_acx_rts_threshold(wl, (u16) value); | ||
991 | if (ret < 0) | ||
992 | wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); | ||
993 | |||
994 | wl12xx_ps_elp_sleep(wl); | ||
995 | |||
996 | out: | ||
997 | mutex_unlock(&wl->mutex); | ||
998 | |||
999 | return ret; | ||
1000 | } | ||
1001 | |||
1002 | static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, | ||
1003 | struct ieee80211_vif *vif, | ||
1004 | struct ieee80211_bss_conf *bss_conf, | ||
1005 | u32 changed) | ||
1006 | { | ||
1007 | enum wl12xx_cmd_ps_mode mode; | ||
1008 | struct wl12xx *wl = hw->priv; | ||
1009 | struct sk_buff *beacon; | ||
1010 | int ret; | ||
1011 | |||
1012 | wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | ||
1013 | |||
1014 | mutex_lock(&wl->mutex); | ||
1015 | |||
1016 | ret = wl12xx_ps_elp_wakeup(wl); | ||
1017 | if (ret < 0) | ||
1018 | goto out; | ||
1019 | |||
1020 | if (changed & BSS_CHANGED_ASSOC) { | ||
1021 | if (bss_conf->assoc) { | ||
1022 | wl->aid = bss_conf->aid; | ||
1023 | |||
1024 | ret = wl12xx_build_ps_poll(wl, wl->aid); | ||
1025 | if (ret < 0) | ||
1026 | goto out_sleep; | ||
1027 | |||
1028 | ret = wl12xx_acx_aid(wl, wl->aid); | ||
1029 | if (ret < 0) | ||
1030 | goto out_sleep; | ||
1031 | |||
1032 | /* If we want to go in PSM but we're not there yet */ | ||
1033 | if (wl->psm_requested && !wl->psm) { | ||
1034 | mode = STATION_POWER_SAVE_MODE; | ||
1035 | ret = wl12xx_ps_set_mode(wl, mode); | ||
1036 | if (ret < 0) | ||
1037 | goto out_sleep; | ||
1038 | } | ||
1039 | } | ||
1040 | } | ||
1041 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1042 | if (bss_conf->use_short_slot) | ||
1043 | ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); | ||
1044 | else | ||
1045 | ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); | ||
1046 | if (ret < 0) { | ||
1047 | wl12xx_warning("Set slot time failed %d", ret); | ||
1048 | goto out_sleep; | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
1053 | if (bss_conf->use_short_preamble) | ||
1054 | wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); | ||
1055 | else | ||
1056 | wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); | ||
1057 | } | ||
1058 | |||
1059 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
1060 | if (bss_conf->use_cts_prot) | ||
1061 | ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); | ||
1062 | else | ||
1063 | ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); | ||
1064 | if (ret < 0) { | ||
1065 | wl12xx_warning("Set ctsprotect failed %d", ret); | ||
1066 | goto out_sleep; | ||
1067 | } | ||
1068 | } | ||
1069 | |||
1070 | if (changed & BSS_CHANGED_BSSID) { | ||
1071 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||
1072 | |||
1073 | ret = wl12xx_build_null_data(wl); | ||
1074 | if (ret < 0) | ||
1075 | goto out; | ||
1076 | |||
1077 | if (wl->bss_type != BSS_TYPE_IBSS) { | ||
1078 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); | ||
1079 | if (ret < 0) | ||
1080 | goto out; | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | if (changed & BSS_CHANGED_BEACON) { | ||
1085 | beacon = ieee80211_beacon_get(hw, vif); | ||
1086 | ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, | ||
1087 | beacon->len); | ||
1088 | |||
1089 | if (ret < 0) { | ||
1090 | dev_kfree_skb(beacon); | ||
1091 | goto out; | ||
1092 | } | ||
1093 | |||
1094 | ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, | ||
1095 | beacon->len); | ||
1096 | |||
1097 | dev_kfree_skb(beacon); | ||
1098 | |||
1099 | if (ret < 0) | ||
1100 | goto out; | ||
1101 | |||
1102 | ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); | ||
1103 | |||
1104 | if (ret < 0) | ||
1105 | goto out; | ||
1106 | } | ||
1107 | |||
1108 | out_sleep: | ||
1109 | wl12xx_ps_elp_sleep(wl); | ||
1110 | |||
1111 | out: | ||
1112 | mutex_unlock(&wl->mutex); | ||
1113 | } | ||
1114 | |||
1115 | |||
1116 | /* can't be const, mac80211 writes to this */ | ||
1117 | static struct ieee80211_rate wl12xx_rates[] = { | ||
1118 | { .bitrate = 10, | ||
1119 | .hw_value = 0x1, | ||
1120 | .hw_value_short = 0x1, }, | ||
1121 | { .bitrate = 20, | ||
1122 | .hw_value = 0x2, | ||
1123 | .hw_value_short = 0x2, | ||
1124 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1125 | { .bitrate = 55, | ||
1126 | .hw_value = 0x4, | ||
1127 | .hw_value_short = 0x4, | ||
1128 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1129 | { .bitrate = 110, | ||
1130 | .hw_value = 0x20, | ||
1131 | .hw_value_short = 0x20, | ||
1132 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
1133 | { .bitrate = 60, | ||
1134 | .hw_value = 0x8, | ||
1135 | .hw_value_short = 0x8, }, | ||
1136 | { .bitrate = 90, | ||
1137 | .hw_value = 0x10, | ||
1138 | .hw_value_short = 0x10, }, | ||
1139 | { .bitrate = 120, | ||
1140 | .hw_value = 0x40, | ||
1141 | .hw_value_short = 0x40, }, | ||
1142 | { .bitrate = 180, | ||
1143 | .hw_value = 0x80, | ||
1144 | .hw_value_short = 0x80, }, | ||
1145 | { .bitrate = 240, | ||
1146 | .hw_value = 0x200, | ||
1147 | .hw_value_short = 0x200, }, | ||
1148 | { .bitrate = 360, | ||
1149 | .hw_value = 0x400, | ||
1150 | .hw_value_short = 0x400, }, | ||
1151 | { .bitrate = 480, | ||
1152 | .hw_value = 0x800, | ||
1153 | .hw_value_short = 0x800, }, | ||
1154 | { .bitrate = 540, | ||
1155 | .hw_value = 0x1000, | ||
1156 | .hw_value_short = 0x1000, }, | ||
1157 | }; | ||
1158 | |||
1159 | /* can't be const, mac80211 writes to this */ | ||
1160 | static struct ieee80211_channel wl12xx_channels[] = { | ||
1161 | { .hw_value = 1, .center_freq = 2412}, | ||
1162 | { .hw_value = 2, .center_freq = 2417}, | ||
1163 | { .hw_value = 3, .center_freq = 2422}, | ||
1164 | { .hw_value = 4, .center_freq = 2427}, | ||
1165 | { .hw_value = 5, .center_freq = 2432}, | ||
1166 | { .hw_value = 6, .center_freq = 2437}, | ||
1167 | { .hw_value = 7, .center_freq = 2442}, | ||
1168 | { .hw_value = 8, .center_freq = 2447}, | ||
1169 | { .hw_value = 9, .center_freq = 2452}, | ||
1170 | { .hw_value = 10, .center_freq = 2457}, | ||
1171 | { .hw_value = 11, .center_freq = 2462}, | ||
1172 | { .hw_value = 12, .center_freq = 2467}, | ||
1173 | { .hw_value = 13, .center_freq = 2472}, | ||
1174 | }; | ||
1175 | |||
1176 | /* can't be const, mac80211 writes to this */ | ||
1177 | static struct ieee80211_supported_band wl12xx_band_2ghz = { | ||
1178 | .channels = wl12xx_channels, | ||
1179 | .n_channels = ARRAY_SIZE(wl12xx_channels), | ||
1180 | .bitrates = wl12xx_rates, | ||
1181 | .n_bitrates = ARRAY_SIZE(wl12xx_rates), | ||
1182 | }; | ||
1183 | |||
1184 | static const struct ieee80211_ops wl12xx_ops = { | ||
1185 | .start = wl12xx_op_start, | ||
1186 | .stop = wl12xx_op_stop, | ||
1187 | .add_interface = wl12xx_op_add_interface, | ||
1188 | .remove_interface = wl12xx_op_remove_interface, | ||
1189 | .config = wl12xx_op_config, | ||
1190 | .configure_filter = wl12xx_op_configure_filter, | ||
1191 | .tx = wl12xx_op_tx, | ||
1192 | .set_key = wl12xx_op_set_key, | ||
1193 | .hw_scan = wl12xx_op_hw_scan, | ||
1194 | .bss_info_changed = wl12xx_op_bss_info_changed, | ||
1195 | .set_rts_threshold = wl12xx_op_set_rts_threshold, | ||
1196 | }; | ||
1197 | |||
1198 | static int wl12xx_register_hw(struct wl12xx *wl) | ||
1199 | { | ||
1200 | int ret; | ||
1201 | |||
1202 | if (wl->mac80211_registered) | ||
1203 | return 0; | ||
1204 | |||
1205 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
1206 | |||
1207 | ret = ieee80211_register_hw(wl->hw); | ||
1208 | if (ret < 0) { | ||
1209 | wl12xx_error("unable to register mac80211 hw: %d", ret); | ||
1210 | return ret; | ||
1211 | } | ||
1212 | |||
1213 | wl->mac80211_registered = true; | ||
1214 | |||
1215 | wl12xx_notice("loaded"); | ||
1216 | |||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | static int wl12xx_init_ieee80211(struct wl12xx *wl) | ||
1221 | { | ||
1222 | /* The tx descriptor buffer and the TKIP space */ | ||
1223 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) | ||
1224 | + WL1251_TKIP_IV_SPACE; | ||
1225 | |||
1226 | /* unit us */ | ||
1227 | /* FIXME: find a proper value */ | ||
1228 | wl->hw->channel_change_time = 10000; | ||
1229 | |||
1230 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
1231 | IEEE80211_HW_NOISE_DBM; | ||
1232 | |||
1233 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
1234 | wl->hw->wiphy->max_scan_ssids = 1; | ||
1235 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; | ||
1236 | |||
1237 | SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | #define WL12XX_DEFAULT_CHANNEL 1 | ||
1243 | static int __devinit wl12xx_probe(struct spi_device *spi) | ||
1244 | { | ||
1245 | struct wl12xx_platform_data *pdata; | ||
1246 | struct ieee80211_hw *hw; | ||
1247 | struct wl12xx *wl; | ||
1248 | int ret, i; | ||
1249 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
1250 | |||
1251 | pdata = spi->dev.platform_data; | ||
1252 | if (!pdata) { | ||
1253 | wl12xx_error("no platform data"); | ||
1254 | return -ENODEV; | ||
1255 | } | ||
1256 | |||
1257 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); | ||
1258 | if (!hw) { | ||
1259 | wl12xx_error("could not alloc ieee80211_hw"); | ||
1260 | return -ENOMEM; | ||
1261 | } | ||
1262 | |||
1263 | wl = hw->priv; | ||
1264 | memset(wl, 0, sizeof(*wl)); | ||
1265 | |||
1266 | wl->hw = hw; | ||
1267 | dev_set_drvdata(&spi->dev, wl); | ||
1268 | wl->spi = spi; | ||
1269 | |||
1270 | wl->data_in_count = 0; | ||
1271 | |||
1272 | skb_queue_head_init(&wl->tx_queue); | ||
1273 | |||
1274 | INIT_WORK(&wl->filter_work, wl12xx_filter_work); | ||
1275 | wl->channel = WL12XX_DEFAULT_CHANNEL; | ||
1276 | wl->scanning = false; | ||
1277 | wl->default_key = 0; | ||
1278 | wl->listen_int = 1; | ||
1279 | wl->rx_counter = 0; | ||
1280 | wl->rx_handled = 0; | ||
1281 | wl->rx_current_buffer = 0; | ||
1282 | wl->rx_last_id = 0; | ||
1283 | wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; | ||
1284 | wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; | ||
1285 | wl->elp = false; | ||
1286 | wl->psm = 0; | ||
1287 | wl->psm_requested = false; | ||
1288 | wl->tx_queue_stopped = false; | ||
1289 | wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; | ||
1290 | |||
1291 | /* We use the default power on sleep time until we know which chip | ||
1292 | * we're using */ | ||
1293 | wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; | ||
1294 | |||
1295 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
1296 | wl->tx_frames[i] = NULL; | ||
1297 | |||
1298 | wl->next_tx_complete = 0; | ||
1299 | |||
1300 | /* | ||
1301 | * In case our MAC address is not correctly set, | ||
1302 | * we use a random but Nokia MAC. | ||
1303 | */ | ||
1304 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
1305 | get_random_bytes(wl->mac_addr + 3, 3); | ||
1306 | |||
1307 | wl->state = WL12XX_STATE_OFF; | ||
1308 | mutex_init(&wl->mutex); | ||
1309 | |||
1310 | wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; | ||
1311 | wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; | ||
1312 | |||
1313 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | ||
1314 | if (!wl->rx_descriptor) { | ||
1315 | wl12xx_error("could not allocate memory for rx descriptor"); | ||
1316 | ret = -ENOMEM; | ||
1317 | goto out_free; | ||
1318 | } | ||
1319 | |||
1320 | /* This is the only SPI value that we need to set here, the rest | ||
1321 | * comes from the board-peripherals file */ | ||
1322 | spi->bits_per_word = 32; | ||
1323 | |||
1324 | ret = spi_setup(spi); | ||
1325 | if (ret < 0) { | ||
1326 | wl12xx_error("spi_setup failed"); | ||
1327 | goto out_free; | ||
1328 | } | ||
1329 | |||
1330 | wl->set_power = pdata->set_power; | ||
1331 | if (!wl->set_power) { | ||
1332 | wl12xx_error("set power function missing in platform data"); | ||
1333 | ret = -ENODEV; | ||
1334 | goto out_free; | ||
1335 | } | ||
1336 | |||
1337 | wl->irq = spi->irq; | ||
1338 | if (wl->irq < 0) { | ||
1339 | wl12xx_error("irq missing in platform data"); | ||
1340 | ret = -ENODEV; | ||
1341 | goto out_free; | ||
1342 | } | ||
1343 | |||
1344 | ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); | ||
1345 | if (ret < 0) { | ||
1346 | wl12xx_error("request_irq() failed: %d", ret); | ||
1347 | goto out_free; | ||
1348 | } | ||
1349 | |||
1350 | set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
1351 | |||
1352 | disable_irq(wl->irq); | ||
1353 | |||
1354 | ret = wl12xx_init_ieee80211(wl); | ||
1355 | if (ret) | ||
1356 | goto out_irq; | ||
1357 | |||
1358 | ret = wl12xx_register_hw(wl); | ||
1359 | if (ret) | ||
1360 | goto out_irq; | ||
1361 | |||
1362 | wl12xx_debugfs_init(wl); | ||
1363 | |||
1364 | wl12xx_notice("initialized"); | ||
1365 | |||
1366 | return 0; | ||
1367 | |||
1368 | out_irq: | ||
1369 | free_irq(wl->irq, wl); | ||
1370 | |||
1371 | out_free: | ||
1372 | kfree(wl->rx_descriptor); | ||
1373 | wl->rx_descriptor = NULL; | ||
1374 | |||
1375 | ieee80211_free_hw(hw); | ||
1376 | |||
1377 | return ret; | ||
1378 | } | ||
1379 | |||
1380 | static int __devexit wl12xx_remove(struct spi_device *spi) | ||
1381 | { | ||
1382 | struct wl12xx *wl = dev_get_drvdata(&spi->dev); | ||
1383 | |||
1384 | ieee80211_unregister_hw(wl->hw); | ||
1385 | |||
1386 | wl12xx_debugfs_exit(wl); | ||
1387 | |||
1388 | free_irq(wl->irq, wl); | ||
1389 | kfree(wl->target_mem_map); | ||
1390 | kfree(wl->data_path); | ||
1391 | kfree(wl->fw); | ||
1392 | wl->fw = NULL; | ||
1393 | kfree(wl->nvs); | ||
1394 | wl->nvs = NULL; | ||
1395 | |||
1396 | kfree(wl->rx_descriptor); | ||
1397 | wl->rx_descriptor = NULL; | ||
1398 | |||
1399 | ieee80211_free_hw(wl->hw); | ||
1400 | |||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | |||
1405 | static struct spi_driver wl12xx_spi_driver = { | ||
1406 | .driver = { | ||
1407 | .name = "wl12xx", | ||
1408 | .bus = &spi_bus_type, | ||
1409 | .owner = THIS_MODULE, | ||
1410 | }, | ||
1411 | |||
1412 | .probe = wl12xx_probe, | ||
1413 | .remove = __devexit_p(wl12xx_remove), | ||
1414 | }; | ||
1415 | |||
1416 | static int __init wl12xx_init(void) | ||
1417 | { | ||
1418 | int ret; | ||
1419 | |||
1420 | ret = spi_register_driver(&wl12xx_spi_driver); | ||
1421 | if (ret < 0) { | ||
1422 | wl12xx_error("failed to register spi driver: %d", ret); | ||
1423 | goto out; | ||
1424 | } | ||
1425 | |||
1426 | out: | ||
1427 | return ret; | ||
1428 | } | ||
1429 | |||
1430 | static void __exit wl12xx_exit(void) | ||
1431 | { | ||
1432 | spi_unregister_driver(&wl12xx_spi_driver); | ||
1433 | |||
1434 | wl12xx_notice("unloaded"); | ||
1435 | } | ||
1436 | |||
1437 | module_init(wl12xx_init); | ||
1438 | module_exit(wl12xx_exit); | ||
1439 | |||
1440 | MODULE_LICENSE("GPL"); | ||
1441 | MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, " | ||
1442 | "Luciano Coelho <luciano.coelho@nokia.com>"); | ||