blob: 282c2bbfec86adbb8b7fb4e199da5c13879de095 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-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/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
37#include "wl1271.h"
38#include "wl12xx_80211.h"
39#include "wl1271_reg.h"
40#include "wl1271_spi.h"
41#include "wl1271_event.h"
42#include "wl1271_tx.h"
43#include "wl1271_rx.h"
44#include "wl1271_ps.h"
45#include "wl1271_init.h"
46#include "wl1271_debugfs.h"
47#include "wl1271_cmd.h"
48#include "wl1271_boot.h"
49
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
54 .per_threshold = 7500,
55 .max_scan_compensation_time = 120000,
56 .nfs_sample_interval = 400,
57 .load_ratio = 50,
58 .auto_ps_mode = 0,
59 .probe_req_compensation = 170,
60 .scan_window_compensation = 50,
61 .antenna_config = 0,
62 .beacon_miss_threshold = 60,
63 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
64 .rate_adaptation_snr = 0
65 },
66 .rx = {
67 .rx_msdu_life_time = 512000,
68 .packet_detection_threshold = 0,
69 .ps_poll_timeout = 15,
70 .upsd_timeout = 15,
71 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020072 .rx_cca_threshold = 0,
73 .irq_blk_threshold = 0xFFFF,
74 .irq_pkt_threshold = 0,
75 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030076 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
77 },
78 .tx = {
79 .tx_energy_detection = 0,
80 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020081 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
82 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030083 .short_retry_limit = 10,
84 .long_retry_limit = 10,
85 .aflags = 0
86 },
87 .ac_conf_count = 4,
88 .ac_conf = {
89 [0] = {
90 .ac = CONF_TX_AC_BE,
91 .cw_min = 15,
92 .cw_max = 63,
93 .aifsn = 3,
94 .tx_op_limit = 0,
95 },
96 [1] = {
97 .ac = CONF_TX_AC_BK,
98 .cw_min = 15,
99 .cw_max = 63,
100 .aifsn = 7,
101 .tx_op_limit = 0,
102 },
103 [2] = {
104 .ac = CONF_TX_AC_VI,
105 .cw_min = 15,
106 .cw_max = 63,
107 .aifsn = CONF_TX_AIFS_PIFS,
108 .tx_op_limit = 3008,
109 },
110 [3] = {
111 .ac = CONF_TX_AC_VO,
112 .cw_min = 15,
113 .cw_max = 63,
114 .aifsn = CONF_TX_AIFS_PIFS,
115 .tx_op_limit = 1504,
116 },
117 },
118 .tid_conf_count = 7,
119 .tid_conf = {
120 [0] = {
121 .queue_id = 0,
122 .channel_type = CONF_CHANNEL_TYPE_DCF,
123 .tsid = CONF_TX_AC_BE,
124 .ps_scheme = CONF_PS_SCHEME_LEGACY,
125 .ack_policy = CONF_ACK_POLICY_LEGACY,
126 .apsd_conf = {0, 0},
127 },
128 [1] = {
129 .queue_id = 1,
130 .channel_type = CONF_CHANNEL_TYPE_DCF,
131 .tsid = CONF_TX_AC_BE,
132 .ps_scheme = CONF_PS_SCHEME_LEGACY,
133 .ack_policy = CONF_ACK_POLICY_LEGACY,
134 .apsd_conf = {0, 0},
135 },
136 [2] = {
137 .queue_id = 2,
138 .channel_type = CONF_CHANNEL_TYPE_DCF,
139 .tsid = CONF_TX_AC_BE,
140 .ps_scheme = CONF_PS_SCHEME_LEGACY,
141 .ack_policy = CONF_ACK_POLICY_LEGACY,
142 .apsd_conf = {0, 0},
143 },
144 [3] = {
145 .queue_id = 3,
146 .channel_type = CONF_CHANNEL_TYPE_DCF,
147 .tsid = CONF_TX_AC_BE,
148 .ps_scheme = CONF_PS_SCHEME_LEGACY,
149 .ack_policy = CONF_ACK_POLICY_LEGACY,
150 .apsd_conf = {0, 0},
151 },
152 [4] = {
153 .queue_id = 4,
154 .channel_type = CONF_CHANNEL_TYPE_DCF,
155 .tsid = CONF_TX_AC_BE,
156 .ps_scheme = CONF_PS_SCHEME_LEGACY,
157 .ack_policy = CONF_ACK_POLICY_LEGACY,
158 .apsd_conf = {0, 0},
159 },
160 [5] = {
161 .queue_id = 5,
162 .channel_type = CONF_CHANNEL_TYPE_DCF,
163 .tsid = CONF_TX_AC_BE,
164 .ps_scheme = CONF_PS_SCHEME_LEGACY,
165 .ack_policy = CONF_ACK_POLICY_LEGACY,
166 .apsd_conf = {0, 0},
167 },
168 [6] = {
169 .queue_id = 6,
170 .channel_type = CONF_CHANNEL_TYPE_DCF,
171 .tsid = CONF_TX_AC_BE,
172 .ps_scheme = CONF_PS_SCHEME_LEGACY,
173 .ack_policy = CONF_ACK_POLICY_LEGACY,
174 .apsd_conf = {0, 0},
175 }
176 },
177 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200178 .tx_compl_timeout = 700,
179 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .conn = {
182 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
183 .listen_interval = 0,
184 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
185 .bcn_filt_ie_count = 1,
186 .bcn_filt_ie = {
187 [0] = {
188 .ie = WLAN_EID_CHANNEL_SWITCH,
189 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
190 }
191 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300193 .bss_lose_timeout = 100,
194 .beacon_rx_timeout = 10000,
195 .broadcast_timeout = 20000,
196 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200197 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .sig_trigger_count = 2,
199 .sig_trigger = {
200 [0] = {
201 .threshold = -75,
202 .pacing = 500,
203 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
204 .type = CONF_TRIG_EVENT_TYPE_EDGE,
205 .direction = CONF_TRIG_EVENT_DIR_LOW,
206 .hysteresis = 2,
207 .index = 0,
208 .enable = 1
209 },
210 [1] = {
211 .threshold = -75,
212 .pacing = 500,
213 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
214 .type = CONF_TRIG_EVENT_TYPE_EDGE,
215 .direction = CONF_TRIG_EVENT_DIR_HIGH,
216 .hysteresis = 2,
217 .index = 1,
218 .enable = 1
219 }
220 },
221 .sig_weights = {
222 .rssi_bcn_avg_weight = 10,
223 .rssi_pkt_avg_weight = 10,
224 .snr_bcn_avg_weight = 10,
225 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300226 },
227 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200228 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200229 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 },
231 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200233 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300234 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200235 },
236 .itrim = {
237 .enable = false,
238 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200239 },
240 .pm_config = {
241 .host_clk_settling_time = 5000,
242 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 }
244};
245
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300246static LIST_HEAD(wl_list);
247
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300248static void wl1271_conf_init(struct wl1271 *wl)
249{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300250
251 /*
252 * This function applies the default configuration to the driver. This
253 * function is invoked upon driver load (spi probe.)
254 *
255 * The configuration is stored in a run-time structure in order to
256 * facilitate for run-time adjustment of any of the parameters. Making
257 * changes to the configuration structure will apply the new values on
258 * the next interface up (wl1271_op_start.)
259 */
260
261 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300262 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300263}
264
265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300266static int wl1271_plt_init(struct wl1271 *wl)
267{
268 int ret;
269
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200270 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200271 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200272 return ret;
273
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200274 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200275 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200276 return ret;
277
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300278 ret = wl1271_acx_init_mem_config(wl);
279 if (ret < 0)
280 return ret;
281
Luciano Coelho94210892009-12-11 15:40:55 +0200282 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300283 if (ret < 0)
284 return ret;
285
286 return 0;
287}
288
289static void wl1271_disable_interrupts(struct wl1271 *wl)
290{
291 disable_irq(wl->irq);
292}
293
294static void wl1271_power_off(struct wl1271 *wl)
295{
296 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200297 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300298}
299
300static void wl1271_power_on(struct wl1271 *wl)
301{
302 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200303 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300304}
305
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300306static void wl1271_fw_status(struct wl1271 *wl,
307 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300308{
309 u32 total = 0;
310 int i;
311
Juuso Oikarinen74621412009-10-12 15:08:54 +0300312 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
313 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300314
315 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
316 "drv_rx_counter = %d, tx_results_counter = %d)",
317 status->intr,
318 status->fw_rx_counter,
319 status->drv_rx_counter,
320 status->tx_results_counter);
321
322 /* update number of available TX blocks */
323 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300324 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
325 wl->tx_blocks_freed[i];
326
327 wl->tx_blocks_freed[i] =
328 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300329 wl->tx_blocks_available += cnt;
330 total += cnt;
331 }
332
333 /* if more blocks are available now, schedule some tx work */
334 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300335 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300336
337 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300338 wl->time_offset = jiffies_to_usecs(jiffies) -
339 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300340}
341
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300342static void wl1271_irq_work(struct work_struct *work)
343{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300344 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300345 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300346 struct wl1271 *wl =
347 container_of(work, struct wl1271, irq_work);
348
349 mutex_lock(&wl->mutex);
350
351 wl1271_debug(DEBUG_IRQ, "IRQ work");
352
353 if (wl->state == WL1271_STATE_OFF)
354 goto out;
355
356 ret = wl1271_ps_elp_wakeup(wl, true);
357 if (ret < 0)
358 goto out;
359
Juuso Oikarinen74621412009-10-12 15:08:54 +0300360 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300362 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300363 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300364 if (!intr) {
365 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
366 goto out_sleep;
367 }
368
369 intr &= WL1271_INTR_MASK;
370
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300371 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300372 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200373 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300374 }
375
376 if (intr & WL1271_ACX_INTR_EVENT_B) {
377 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200378 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300379 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300380
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300381 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
382 wl1271_debug(DEBUG_IRQ,
383 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300384
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300385 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
386 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300388 if (intr & WL1271_ACX_INTR_DATA) {
389 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
390 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300391
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300392 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300393
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300394 /* check for tx results */
395 if (tx_res_cnt)
396 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300397
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300398 wl1271_rx(wl, wl->fw_status);
399 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300400
401out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300402 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300403 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404 wl1271_ps_elp_sleep(wl);
405
406out:
407 mutex_unlock(&wl->mutex);
408}
409
410static irqreturn_t wl1271_irq(int irq, void *cookie)
411{
412 struct wl1271 *wl;
413 unsigned long flags;
414
415 wl1271_debug(DEBUG_IRQ, "IRQ");
416
417 wl = cookie;
418
419 /* complete the ELP completion */
420 spin_lock_irqsave(&wl->wl_lock, flags);
421 if (wl->elp_compl) {
422 complete(wl->elp_compl);
423 wl->elp_compl = NULL;
424 }
425
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300426 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427 spin_unlock_irqrestore(&wl->wl_lock, flags);
428
429 return IRQ_HANDLED;
430}
431
432static int wl1271_fetch_firmware(struct wl1271 *wl)
433{
434 const struct firmware *fw;
435 int ret;
436
437 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
438
439 if (ret < 0) {
440 wl1271_error("could not get firmware: %d", ret);
441 return ret;
442 }
443
444 if (fw->size % 4) {
445 wl1271_error("firmware size is not multiple of 32 bits: %zu",
446 fw->size);
447 ret = -EILSEQ;
448 goto out;
449 }
450
451 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300452 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300453
454 if (!wl->fw) {
455 wl1271_error("could not allocate memory for the firmware");
456 ret = -ENOMEM;
457 goto out;
458 }
459
460 memcpy(wl->fw, fw->data, wl->fw_len);
461
462 ret = 0;
463
464out:
465 release_firmware(fw);
466
467 return ret;
468}
469
470static int wl1271_fetch_nvs(struct wl1271 *wl)
471{
472 const struct firmware *fw;
473 int ret;
474
475 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
476
477 if (ret < 0) {
478 wl1271_error("could not get nvs file: %d", ret);
479 return ret;
480 }
481
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200482 if (fw->size != sizeof(struct wl1271_nvs_file)) {
483 wl1271_error("nvs size is not as expected: %zu != %zu",
484 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300485 ret = -EILSEQ;
486 goto out;
487 }
488
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200489 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300490
491 if (!wl->nvs) {
492 wl1271_error("could not allocate memory for the nvs file");
493 ret = -ENOMEM;
494 goto out;
495 }
496
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200497 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498
499 ret = 0;
500
501out:
502 release_firmware(fw);
503
504 return ret;
505}
506
507static void wl1271_fw_wakeup(struct wl1271 *wl)
508{
509 u32 elp_reg;
510
511 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300512 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513}
514
515static int wl1271_setup(struct wl1271 *wl)
516{
517 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
518 if (!wl->fw_status)
519 return -ENOMEM;
520
521 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
522 if (!wl->tx_res_if) {
523 kfree(wl->fw_status);
524 return -ENOMEM;
525 }
526
527 INIT_WORK(&wl->irq_work, wl1271_irq_work);
528 INIT_WORK(&wl->tx_work, wl1271_tx_work);
529 return 0;
530}
531
532static int wl1271_chip_wakeup(struct wl1271 *wl)
533{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300534 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300535 int ret = 0;
536
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200537 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538 wl1271_power_on(wl);
539 msleep(WL1271_POWER_ON_SLEEP);
540 wl1271_spi_reset(wl);
541 wl1271_spi_init(wl);
542
543 /* We don't need a real memory partition here, because we only want
544 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300545 memset(&partition, 0, sizeof(partition));
546 partition.reg.start = REGISTERS_BASE;
547 partition.reg.size = REGISTERS_DOWN_SIZE;
548 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300549
550 /* ELP module wake up */
551 wl1271_fw_wakeup(wl);
552
553 /* whal_FwCtrl_BootSm() */
554
555 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300556 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300557
558 /* 1. check if chip id is valid */
559
560 switch (wl->chip.id) {
561 case CHIP_ID_1271_PG10:
562 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
563 wl->chip.id);
564
565 ret = wl1271_setup(wl);
566 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200567 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300568 break;
569 case CHIP_ID_1271_PG20:
570 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
571 wl->chip.id);
572
573 ret = wl1271_setup(wl);
574 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200575 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300576 break;
577 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200578 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200580 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581 }
582
583 if (wl->fw == NULL) {
584 ret = wl1271_fetch_firmware(wl);
585 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200586 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587 }
588
589 /* No NVS from netlink, try to get it from the filesystem */
590 if (wl->nvs == NULL) {
591 ret = wl1271_fetch_nvs(wl);
592 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200593 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300594 }
595
596out:
597 return ret;
598}
599
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600int wl1271_plt_start(struct wl1271 *wl)
601{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200602 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300603 int ret;
604
605 mutex_lock(&wl->mutex);
606
607 wl1271_notice("power up");
608
609 if (wl->state != WL1271_STATE_OFF) {
610 wl1271_error("cannot go into PLT state because not "
611 "in off state: %d", wl->state);
612 ret = -EBUSY;
613 goto out;
614 }
615
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200616 while (retries) {
617 retries--;
618 ret = wl1271_chip_wakeup(wl);
619 if (ret < 0)
620 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200622 ret = wl1271_boot(wl);
623 if (ret < 0)
624 goto power_off;
625
626 ret = wl1271_plt_init(wl);
627 if (ret < 0)
628 goto irq_disable;
629
630 /* Make sure power saving is disabled */
631 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
632 if (ret < 0)
633 goto irq_disable;
634
635 wl->state = WL1271_STATE_PLT;
636 wl1271_notice("firmware booted in PLT mode (%s)",
637 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638 goto out;
639
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200640irq_disable:
641 wl1271_disable_interrupts(wl);
642 mutex_unlock(&wl->mutex);
643 /* Unlocking the mutex in the middle of handling is
644 inherently unsafe. In this case we deem it safe to do,
645 because we need to let any possibly pending IRQ out of
646 the system (and while we are WL1271_STATE_OFF the IRQ
647 work function will not do anything.) Also, any other
648 possible concurrent operations will fail due to the
649 current state, hence the wl1271 struct should be safe. */
650 cancel_work_sync(&wl->irq_work);
651 mutex_lock(&wl->mutex);
652power_off:
653 wl1271_power_off(wl);
654 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200656 wl1271_error("firmware boot in PLT mode failed despite %d retries",
657 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658out:
659 mutex_unlock(&wl->mutex);
660
661 return ret;
662}
663
664int wl1271_plt_stop(struct wl1271 *wl)
665{
666 int ret = 0;
667
668 mutex_lock(&wl->mutex);
669
670 wl1271_notice("power down");
671
672 if (wl->state != WL1271_STATE_PLT) {
673 wl1271_error("cannot power down because not in PLT "
674 "state: %d", wl->state);
675 ret = -EBUSY;
676 goto out;
677 }
678
679 wl1271_disable_interrupts(wl);
680 wl1271_power_off(wl);
681
682 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300683 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684
685out:
686 mutex_unlock(&wl->mutex);
687
688 return ret;
689}
690
691
692static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
693{
694 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200695 struct ieee80211_conf *conf = &hw->conf;
696 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
697 struct ieee80211_sta *sta = txinfo->control.sta;
698 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200700 /* peek into the rates configured in the STA entry */
701 spin_lock_irqsave(&wl->wl_lock, flags);
702 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
703 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
704 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
705 }
706 spin_unlock_irqrestore(&wl->wl_lock, flags);
707
708 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709 skb_queue_tail(&wl->tx_queue, skb);
710
711 /*
712 * The chip specific setup must run before the first TX packet -
713 * before that, the tx_work will not be initialized!
714 */
715
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300716 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717
718 /*
719 * The workqueue is slow to process the tx_queue and we need stop
720 * the queue here, otherwise the queue will get too long.
721 */
722 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
723 ieee80211_stop_queues(wl->hw);
724
725 /*
726 * FIXME: this is racy, the variable is not properly
727 * protected. Maybe fix this by removing the stupid
728 * variable altogether and checking the real queue state?
729 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200730 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731 }
732
733 return NETDEV_TX_OK;
734}
735
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300736static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
737 void *arg)
738{
739 struct net_device *dev;
740 struct wireless_dev *wdev;
741 struct wiphy *wiphy;
742 struct ieee80211_hw *hw;
743 struct wl1271 *wl;
744 struct wl1271 *wl_temp;
745 struct in_device *idev;
746 struct in_ifaddr *ifa = arg;
747 int ret = 0;
748
749 /* FIXME: this ugly function should probably be implemented in the
750 * mac80211, and here should only be a simple callback handling actual
751 * setting of the filters. Now we need to dig up references to
752 * various structures to gain access to what we need.
753 * Also, because of this, there is no "initial" setting of the filter
754 * in "op_start", because we don't want to dig up struct net_device
755 * there - the filter will be set upon first change of the interface
756 * IP address. */
757
758 dev = ifa->ifa_dev->dev;
759
760 wdev = dev->ieee80211_ptr;
761 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200762 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300763
764 wiphy = wdev->wiphy;
765 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200766 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300767
768 hw = wiphy_priv(wiphy);
769 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200770 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300771
772 /* Check that the interface is one supported by this driver. */
773 wl_temp = hw->priv;
774 list_for_each_entry(wl, &wl_list, list) {
775 if (wl == wl_temp)
776 break;
777 }
778 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200779 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300780
781 /* Get the interface IP address for the device. "ifa" will become
782 NULL if:
783 - there is no IPV4 protocol address configured
784 - there are multiple (virtual) IPV4 addresses configured
785 When "ifa" is NULL, filtering will be disabled.
786 */
787 ifa = NULL;
788 idev = dev->ip_ptr;
789 if (idev)
790 ifa = idev->ifa_list;
791
792 if (ifa && ifa->ifa_next)
793 ifa = NULL;
794
795 mutex_lock(&wl->mutex);
796
797 if (wl->state == WL1271_STATE_OFF)
798 goto out;
799
800 ret = wl1271_ps_elp_wakeup(wl, false);
801 if (ret < 0)
802 goto out;
803 if (ifa)
804 ret = wl1271_acx_arp_ip_filter(wl, true,
805 (u8 *)&ifa->ifa_address,
806 ACX_IPV4_VERSION);
807 else
808 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
809 ACX_IPV4_VERSION);
810 wl1271_ps_elp_sleep(wl);
811
812out:
813 mutex_unlock(&wl->mutex);
814
Luciano Coelho17d72652009-11-23 23:22:15 +0200815 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300816}
817
818static struct notifier_block wl1271_dev_notifier = {
819 .notifier_call = wl1271_dev_notify,
820};
821
822
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300823static int wl1271_op_start(struct ieee80211_hw *hw)
824{
825 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200826 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827 int ret = 0;
828
829 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
830
831 mutex_lock(&wl->mutex);
832
833 if (wl->state != WL1271_STATE_OFF) {
834 wl1271_error("cannot start because not in off state: %d",
835 wl->state);
836 ret = -EBUSY;
837 goto out;
838 }
839
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200840 while (retries) {
841 retries--;
842 ret = wl1271_chip_wakeup(wl);
843 if (ret < 0)
844 goto power_off;
845
846 ret = wl1271_boot(wl);
847 if (ret < 0)
848 goto power_off;
849
850 ret = wl1271_hw_init(wl);
851 if (ret < 0)
852 goto irq_disable;
853
854 wl->state = WL1271_STATE_ON;
855 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856 goto out;
857
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200858irq_disable:
859 wl1271_disable_interrupts(wl);
860 mutex_unlock(&wl->mutex);
861 /* Unlocking the mutex in the middle of handling is
862 inherently unsafe. In this case we deem it safe to do,
863 because we need to let any possibly pending IRQ out of
864 the system (and while we are WL1271_STATE_OFF the IRQ
865 work function will not do anything.) Also, any other
866 possible concurrent operations will fail due to the
867 current state, hence the wl1271 struct should be safe. */
868 cancel_work_sync(&wl->irq_work);
869 mutex_lock(&wl->mutex);
870power_off:
871 wl1271_power_off(wl);
872 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200874 wl1271_error("firmware boot failed despite %d retries",
875 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300876out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877 mutex_unlock(&wl->mutex);
878
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300879 if (!ret) {
880 list_add(&wl->list, &wl_list);
881 register_inetaddr_notifier(&wl1271_dev_notifier);
882 }
883
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884 return ret;
885}
886
887static void wl1271_op_stop(struct ieee80211_hw *hw)
888{
889 struct wl1271 *wl = hw->priv;
890 int i;
891
892 wl1271_info("down");
893
894 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
895
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300896 unregister_inetaddr_notifier(&wl1271_dev_notifier);
897 list_del(&wl->list);
898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 mutex_lock(&wl->mutex);
900
901 WARN_ON(wl->state != WL1271_STATE_ON);
902
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200903 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904 mutex_unlock(&wl->mutex);
905 ieee80211_scan_completed(wl->hw, true);
906 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907 }
908
909 wl->state = WL1271_STATE_OFF;
910
911 wl1271_disable_interrupts(wl);
912
913 mutex_unlock(&wl->mutex);
914
915 cancel_work_sync(&wl->irq_work);
916 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917
918 mutex_lock(&wl->mutex);
919
920 /* let's notify MAC80211 about the remaining pending TX frames */
921 wl1271_tx_flush(wl);
922 wl1271_power_off(wl);
923
924 memset(wl->bssid, 0, ETH_ALEN);
925 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
926 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300928 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929
930 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200931 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
933 wl->tx_blocks_available = 0;
934 wl->tx_results_count = 0;
935 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300936 wl->tx_security_last_seq = 0;
937 wl->tx_security_seq_16 = 0;
938 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 wl->time_offset = 0;
940 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200941 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
942 wl->sta_rate_set = 0;
943 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 for (i = 0; i < NUM_TX_QUEUES; i++)
946 wl->tx_blocks_freed[i] = 0;
947
948 wl1271_debugfs_reset(wl);
949 mutex_unlock(&wl->mutex);
950}
951
952static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +0100953 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954{
955 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 int ret = 0;
957
John W. Linvillee5539bc2009-08-18 10:50:34 -0400958 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +0100959 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960
961 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300962 if (wl->vif) {
963 ret = -EBUSY;
964 goto out;
965 }
966
Johannes Berg1ed32e42009-12-23 13:15:45 +0100967 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968
Johannes Berg1ed32e42009-12-23 13:15:45 +0100969 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 case NL80211_IFTYPE_STATION:
971 wl->bss_type = BSS_TYPE_STA_BSS;
972 break;
973 case NL80211_IFTYPE_ADHOC:
974 wl->bss_type = BSS_TYPE_IBSS;
975 break;
976 default:
977 ret = -EOPNOTSUPP;
978 goto out;
979 }
980
981 /* FIXME: what if conf->mac_addr changes? */
982
983out:
984 mutex_unlock(&wl->mutex);
985 return ret;
986}
987
988static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +0100989 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300991 struct wl1271 *wl = hw->priv;
992
993 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300995 wl->vif = NULL;
996 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997}
998
999#if 0
1000static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1001 struct ieee80211_vif *vif,
1002 struct ieee80211_if_conf *conf)
1003{
1004 struct wl1271 *wl = hw->priv;
1005 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 int ret;
1007
David S. Miller32646902009-09-17 10:18:30 -07001008 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1009 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1011 conf->ssid_len);
1012
1013 mutex_lock(&wl->mutex);
1014
1015 ret = wl1271_ps_elp_wakeup(wl, false);
1016 if (ret < 0)
1017 goto out;
1018
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001019 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1020 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1021
1022 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1023
1024 ret = wl1271_cmd_join(wl);
1025 if (ret < 0)
1026 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001028 ret = wl1271_cmd_build_null_data(wl);
1029 if (ret < 0)
1030 goto out_sleep;
1031 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032
1033 wl->ssid_len = conf->ssid_len;
1034 if (wl->ssid_len)
1035 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 if (conf->changed & IEEE80211_IFCC_BEACON) {
1038 beacon = ieee80211_beacon_get(hw, vif);
1039 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1040 beacon->data, beacon->len);
1041
1042 if (ret < 0) {
1043 dev_kfree_skb(beacon);
1044 goto out_sleep;
1045 }
1046
1047 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1048 beacon->data, beacon->len);
1049
1050 dev_kfree_skb(beacon);
1051
1052 if (ret < 0)
1053 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 }
1055
1056out_sleep:
1057 wl1271_ps_elp_sleep(wl);
1058
1059out:
1060 mutex_unlock(&wl->mutex);
1061
1062 return ret;
1063}
1064#endif
1065
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001066static int wl1271_join_channel(struct wl1271 *wl, int channel)
1067{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001068 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001069 /* we need to use a dummy BSSID for now */
1070 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1071 0xad, 0xbe, 0xef };
1072
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001073 /* the dummy join is not required for ad-hoc */
1074 if (wl->bss_type == BSS_TYPE_IBSS)
1075 goto out;
1076
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001077 /* disable mac filter, so we hear everything */
1078 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1079
1080 wl->channel = channel;
1081 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1082
1083 ret = wl1271_cmd_join(wl);
1084 if (ret < 0)
1085 goto out;
1086
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001087 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001088
1089out:
1090 return ret;
1091}
1092
1093static int wl1271_unjoin_channel(struct wl1271 *wl)
1094{
1095 int ret;
1096
1097 /* to stop listening to a channel, we disconnect */
1098 ret = wl1271_cmd_disconnect(wl);
1099 if (ret < 0)
1100 goto out;
1101
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001102 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001103 wl->channel = 0;
1104 memset(wl->bssid, 0, ETH_ALEN);
1105 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1106
1107out:
1108 return ret;
1109}
1110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1112{
1113 struct wl1271 *wl = hw->priv;
1114 struct ieee80211_conf *conf = &hw->conf;
1115 int channel, ret = 0;
1116
1117 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1118
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001119 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120 channel,
1121 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001122 conf->power_level,
1123 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001124
1125 mutex_lock(&wl->mutex);
1126
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001127 wl->band = conf->channel->band;
1128
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129 ret = wl1271_ps_elp_wakeup(wl, false);
1130 if (ret < 0)
1131 goto out;
1132
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001134 if (conf->flags & IEEE80211_CONF_IDLE &&
1135 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001136 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001137 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001138 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001139
1140 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001141 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1142 wl->sta_rate_set = 0;
1143 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001144 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001145 }
1146
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001147 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001148 if (channel != wl->channel &&
1149 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1150 wl->channel = channel;
1151 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
1152 ret = wl1271_cmd_join(wl);
1153 if (ret < 0)
1154 wl1271_warning("cmd join to update channel failed %d",
1155 ret);
1156 } else
1157 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001158
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001159 if (conf->flags & IEEE80211_CONF_PS &&
1160 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1161 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001162
1163 /*
1164 * We enter PSM only if we're already associated.
1165 * If we're not, we'll enter it when joining an SSID,
1166 * through the bss_info_changed() hook.
1167 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001168 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001169 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001170 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1171 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001172 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001174 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175 wl1271_info("psm disabled");
1176
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001177 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001179 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001180 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1181 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182 }
1183
1184 if (conf->power_level != wl->power_level) {
1185 ret = wl1271_acx_tx_power(wl, conf->power_level);
1186 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001187 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001188
1189 wl->power_level = conf->power_level;
1190 }
1191
1192out_sleep:
1193 wl1271_ps_elp_sleep(wl);
1194
1195out:
1196 mutex_unlock(&wl->mutex);
1197
1198 return ret;
1199}
1200
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001201struct wl1271_filter_params {
1202 bool enabled;
1203 int mc_list_length;
1204 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1205};
1206
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001207static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1208 struct dev_addr_list *mc_list)
1209{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001210 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001211 int i;
1212
Juuso Oikarinen74441132009-10-13 12:47:53 +03001213 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001214 if (!fp) {
1215 wl1271_error("Out of memory setting filters.");
1216 return 0;
1217 }
1218
1219 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001220 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001221 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1222 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001223 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001224 }
1225
1226 fp->mc_list_length = 0;
1227 for (i = 0; i < mc_count; i++) {
1228 if (mc_list->da_addrlen == ETH_ALEN) {
1229 memcpy(fp->mc_list[fp->mc_list_length],
1230 mc_list->da_addr, ETH_ALEN);
1231 fp->mc_list_length++;
1232 } else
1233 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001234 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001235 }
1236
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001237 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001238}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001240#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1241 FIF_ALLMULTI | \
1242 FIF_FCSFAIL | \
1243 FIF_BCN_PRBRESP_PROMISC | \
1244 FIF_CONTROL | \
1245 FIF_OTHER_BSS)
1246
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1248 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001249 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001251 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001253 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1256
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001257 mutex_lock(&wl->mutex);
1258
1259 if (wl->state == WL1271_STATE_OFF)
1260 goto out;
1261
1262 ret = wl1271_ps_elp_wakeup(wl, false);
1263 if (ret < 0)
1264 goto out;
1265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 *total &= WL1271_SUPPORTED_FILTERS;
1267 changed &= WL1271_SUPPORTED_FILTERS;
1268
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001269 if (*total & FIF_ALLMULTI)
1270 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1271 else if (fp)
1272 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1273 fp->mc_list,
1274 fp->mc_list_length);
1275 if (ret < 0)
1276 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001277
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001278 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001279
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001280 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001281
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001282 /* determine, whether supported filter values have changed */
1283 if (changed == 0)
1284 goto out_sleep;
1285
1286 /* apply configured filters */
1287 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1288 if (ret < 0)
1289 goto out_sleep;
1290
1291out_sleep:
1292 wl1271_ps_elp_sleep(wl);
1293
1294out:
1295 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296}
1297
1298static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1299 struct ieee80211_vif *vif,
1300 struct ieee80211_sta *sta,
1301 struct ieee80211_key_conf *key_conf)
1302{
1303 struct wl1271 *wl = hw->priv;
1304 const u8 *addr;
1305 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001306 u32 tx_seq_32 = 0;
1307 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 u8 key_type;
1309
1310 static const u8 bcast_addr[ETH_ALEN] =
1311 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1312
1313 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1314
1315 addr = sta ? sta->addr : bcast_addr;
1316
1317 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1318 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1319 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1320 key_conf->alg, key_conf->keyidx,
1321 key_conf->keylen, key_conf->flags);
1322 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1323
1324 if (is_zero_ether_addr(addr)) {
1325 /* We dont support TX only encryption */
1326 ret = -EOPNOTSUPP;
1327 goto out;
1328 }
1329
1330 mutex_lock(&wl->mutex);
1331
1332 ret = wl1271_ps_elp_wakeup(wl, false);
1333 if (ret < 0)
1334 goto out_unlock;
1335
1336 switch (key_conf->alg) {
1337 case ALG_WEP:
1338 key_type = KEY_WEP;
1339
1340 key_conf->hw_key_idx = key_conf->keyidx;
1341 break;
1342 case ALG_TKIP:
1343 key_type = KEY_TKIP;
1344
1345 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001346 tx_seq_32 = wl->tx_security_seq_32;
1347 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348 break;
1349 case ALG_CCMP:
1350 key_type = KEY_AES;
1351
1352 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001353 tx_seq_32 = wl->tx_security_seq_32;
1354 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 break;
1356 default:
1357 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1358
1359 ret = -EOPNOTSUPP;
1360 goto out_sleep;
1361 }
1362
1363 switch (cmd) {
1364 case SET_KEY:
1365 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1366 key_conf->keyidx, key_type,
1367 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001368 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369 if (ret < 0) {
1370 wl1271_error("Could not add or replace key");
1371 goto out_sleep;
1372 }
1373 break;
1374
1375 case DISABLE_KEY:
1376 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1377 key_conf->keyidx, key_type,
1378 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001379 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 if (ret < 0) {
1381 wl1271_error("Could not remove key");
1382 goto out_sleep;
1383 }
1384 break;
1385
1386 default:
1387 wl1271_error("Unsupported key cmd 0x%x", cmd);
1388 ret = -EOPNOTSUPP;
1389 goto out_sleep;
1390
1391 break;
1392 }
1393
1394out_sleep:
1395 wl1271_ps_elp_sleep(wl);
1396
1397out_unlock:
1398 mutex_unlock(&wl->mutex);
1399
1400out:
1401 return ret;
1402}
1403
1404static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1405 struct cfg80211_scan_request *req)
1406{
1407 struct wl1271 *wl = hw->priv;
1408 int ret;
1409 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001410 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
1412 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1413
1414 if (req->n_ssids) {
1415 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001416 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 }
1418
1419 mutex_lock(&wl->mutex);
1420
1421 ret = wl1271_ps_elp_wakeup(wl, false);
1422 if (ret < 0)
1423 goto out;
1424
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001425 if (wl1271_11a_enabled())
1426 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1427 WL1271_SCAN_BAND_DUAL, 3);
1428 else
1429 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1430 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431
1432 wl1271_ps_elp_sleep(wl);
1433
1434out:
1435 mutex_unlock(&wl->mutex);
1436
1437 return ret;
1438}
1439
1440static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1441{
1442 struct wl1271 *wl = hw->priv;
1443 int ret;
1444
1445 mutex_lock(&wl->mutex);
1446
1447 ret = wl1271_ps_elp_wakeup(wl, false);
1448 if (ret < 0)
1449 goto out;
1450
1451 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1452 if (ret < 0)
1453 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1454
1455 wl1271_ps_elp_sleep(wl);
1456
1457out:
1458 mutex_unlock(&wl->mutex);
1459
1460 return ret;
1461}
1462
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001463static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1464{
1465 u8 *ptr = beacon->data +
1466 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1467
1468 /* find the location of the ssid in the beacon */
1469 while (ptr < beacon->data + beacon->len) {
1470 if (ptr[0] == WLAN_EID_SSID) {
1471 wl->ssid_len = ptr[1];
1472 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1473 return;
1474 }
1475 ptr += ptr[1];
1476 }
1477 wl1271_error("ad-hoc beacon template has no SSID!\n");
1478}
1479
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1481 struct ieee80211_vif *vif,
1482 struct ieee80211_bss_conf *bss_conf,
1483 u32 changed)
1484{
1485 enum wl1271_cmd_ps_mode mode;
1486 struct wl1271 *wl = hw->priv;
1487 int ret;
1488
1489 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1490
1491 mutex_lock(&wl->mutex);
1492
1493 ret = wl1271_ps_elp_wakeup(wl, false);
1494 if (ret < 0)
1495 goto out;
1496
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001497 if (wl->bss_type == BSS_TYPE_IBSS) {
1498 /* FIXME: This implements rudimentary ad-hoc support -
1499 proper templates are on the wish list and notification
1500 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001501 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001502 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1503
1504 if (beacon) {
1505 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001506
1507 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001508 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1509 beacon->data,
1510 beacon->len);
1511
1512 if (ret < 0) {
1513 dev_kfree_skb(beacon);
1514 goto out_sleep;
1515 }
1516
1517 hdr = (struct ieee80211_hdr *) beacon->data;
1518 hdr->frame_control = cpu_to_le16(
1519 IEEE80211_FTYPE_MGMT |
1520 IEEE80211_STYPE_PROBE_RESP);
1521
1522 ret = wl1271_cmd_template_set(wl,
1523 CMD_TEMPL_PROBE_RESPONSE,
1524 beacon->data,
1525 beacon->len);
1526 dev_kfree_skb(beacon);
1527 if (ret < 0)
1528 goto out_sleep;
1529 }
1530 }
1531
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001532 if ((changed & BSS_CHANGED_BSSID) &&
1533 /*
1534 * Now we know the correct bssid, so we send a new join command
1535 * and enable the BSSID filter
1536 */
1537 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1538 wl->rx_config |= CFG_BSSID_FILTER_EN;
1539 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1540 ret = wl1271_cmd_build_null_data(wl);
1541 if (ret < 0) {
1542 wl1271_warning("cmd buld null data failed %d",
1543 ret);
1544 goto out_sleep;
1545 }
1546
1547 ret = wl1271_cmd_join(wl);
1548 if (ret < 0) {
1549 wl1271_warning("cmd join failed %d", ret);
1550 goto out_sleep;
1551 }
1552 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1553 }
1554
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001555 if (changed & BSS_CHANGED_ASSOC) {
1556 if (bss_conf->assoc) {
1557 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001558 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001560 /*
1561 * with wl1271, we don't need to update the
1562 * beacon_int and dtim_period, because the firmware
1563 * updates it by itself when the first beacon is
1564 * received after a join.
1565 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1567 if (ret < 0)
1568 goto out_sleep;
1569
1570 ret = wl1271_acx_aid(wl, wl->aid);
1571 if (ret < 0)
1572 goto out_sleep;
1573
1574 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001575 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1576 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001578 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 if (ret < 0)
1580 goto out_sleep;
1581 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001582 } else {
1583 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001584 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001585 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001589
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590 if (changed & BSS_CHANGED_ERP_SLOT) {
1591 if (bss_conf->use_short_slot)
1592 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1593 else
1594 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1595 if (ret < 0) {
1596 wl1271_warning("Set slot time failed %d", ret);
1597 goto out_sleep;
1598 }
1599 }
1600
1601 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1602 if (bss_conf->use_short_preamble)
1603 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1604 else
1605 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1606 }
1607
1608 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1609 if (bss_conf->use_cts_prot)
1610 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1611 else
1612 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1613 if (ret < 0) {
1614 wl1271_warning("Set ctsprotect failed %d", ret);
1615 goto out_sleep;
1616 }
1617 }
1618
1619out_sleep:
1620 wl1271_ps_elp_sleep(wl);
1621
1622out:
1623 mutex_unlock(&wl->mutex);
1624}
1625
Kalle Valoc6999d82010-02-18 13:25:41 +02001626static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1627 const struct ieee80211_tx_queue_params *params)
1628{
1629 struct wl1271 *wl = hw->priv;
1630 int ret;
1631
1632 mutex_lock(&wl->mutex);
1633
1634 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1635
1636 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1637 params->cw_min, params->cw_max,
1638 params->aifs, params->txop);
1639 if (ret < 0)
1640 goto out;
1641
1642 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1643 CONF_CHANNEL_TYPE_EDCF,
1644 wl1271_tx_get_queue(queue),
1645 CONF_PS_SCHEME_LEGACY_PSPOLL,
1646 CONF_ACK_POLICY_LEGACY, 0, 0);
1647 if (ret < 0)
1648 goto out;
1649
1650out:
1651 mutex_unlock(&wl->mutex);
1652
1653 return ret;
1654}
1655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656
1657/* can't be const, mac80211 writes to this */
1658static struct ieee80211_rate wl1271_rates[] = {
1659 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001660 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1661 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001663 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1664 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1666 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001667 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1668 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001669 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1670 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001671 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1672 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001673 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1674 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001675 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1676 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001678 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1679 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001680 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001681 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1682 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001683 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001684 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1685 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001687 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1688 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001689 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001690 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1691 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001692 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001693 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1694 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001695 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001696 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1697 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698};
1699
1700/* can't be const, mac80211 writes to this */
1701static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001702 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1703 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1704 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1705 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1706 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1707 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1708 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1709 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1710 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1711 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1712 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1713 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1714 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715};
1716
1717/* can't be const, mac80211 writes to this */
1718static struct ieee80211_supported_band wl1271_band_2ghz = {
1719 .channels = wl1271_channels,
1720 .n_channels = ARRAY_SIZE(wl1271_channels),
1721 .bitrates = wl1271_rates,
1722 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1723};
1724
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001725/* 5 GHz data rates for WL1273 */
1726static struct ieee80211_rate wl1271_rates_5ghz[] = {
1727 { .bitrate = 60,
1728 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1729 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1730 { .bitrate = 90,
1731 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1732 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1733 { .bitrate = 120,
1734 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1735 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1736 { .bitrate = 180,
1737 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1738 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1739 { .bitrate = 240,
1740 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1741 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1742 { .bitrate = 360,
1743 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1744 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1745 { .bitrate = 480,
1746 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1747 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1748 { .bitrate = 540,
1749 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1750 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1751};
1752
1753/* 5 GHz band channels for WL1273 */
1754static struct ieee80211_channel wl1271_channels_5ghz[] = {
1755 { .hw_value = 183, .center_freq = 4915},
1756 { .hw_value = 184, .center_freq = 4920},
1757 { .hw_value = 185, .center_freq = 4925},
1758 { .hw_value = 187, .center_freq = 4935},
1759 { .hw_value = 188, .center_freq = 4940},
1760 { .hw_value = 189, .center_freq = 4945},
1761 { .hw_value = 192, .center_freq = 4960},
1762 { .hw_value = 196, .center_freq = 4980},
1763 { .hw_value = 7, .center_freq = 5035},
1764 { .hw_value = 8, .center_freq = 5040},
1765 { .hw_value = 9, .center_freq = 5045},
1766 { .hw_value = 11, .center_freq = 5055},
1767 { .hw_value = 12, .center_freq = 5060},
1768 { .hw_value = 16, .center_freq = 5080},
1769 { .hw_value = 34, .center_freq = 5170},
1770 { .hw_value = 36, .center_freq = 5180},
1771 { .hw_value = 38, .center_freq = 5190},
1772 { .hw_value = 40, .center_freq = 5200},
1773 { .hw_value = 42, .center_freq = 5210},
1774 { .hw_value = 44, .center_freq = 5220},
1775 { .hw_value = 46, .center_freq = 5230},
1776 { .hw_value = 48, .center_freq = 5240},
1777 { .hw_value = 52, .center_freq = 5260},
1778 { .hw_value = 56, .center_freq = 5280},
1779 { .hw_value = 60, .center_freq = 5300},
1780 { .hw_value = 64, .center_freq = 5320},
1781 { .hw_value = 100, .center_freq = 5500},
1782 { .hw_value = 104, .center_freq = 5520},
1783 { .hw_value = 108, .center_freq = 5540},
1784 { .hw_value = 112, .center_freq = 5560},
1785 { .hw_value = 116, .center_freq = 5580},
1786 { .hw_value = 120, .center_freq = 5600},
1787 { .hw_value = 124, .center_freq = 5620},
1788 { .hw_value = 128, .center_freq = 5640},
1789 { .hw_value = 132, .center_freq = 5660},
1790 { .hw_value = 136, .center_freq = 5680},
1791 { .hw_value = 140, .center_freq = 5700},
1792 { .hw_value = 149, .center_freq = 5745},
1793 { .hw_value = 153, .center_freq = 5765},
1794 { .hw_value = 157, .center_freq = 5785},
1795 { .hw_value = 161, .center_freq = 5805},
1796 { .hw_value = 165, .center_freq = 5825},
1797};
1798
1799
1800static struct ieee80211_supported_band wl1271_band_5ghz = {
1801 .channels = wl1271_channels_5ghz,
1802 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1803 .bitrates = wl1271_rates_5ghz,
1804 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1805};
1806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807static const struct ieee80211_ops wl1271_ops = {
1808 .start = wl1271_op_start,
1809 .stop = wl1271_op_stop,
1810 .add_interface = wl1271_op_add_interface,
1811 .remove_interface = wl1271_op_remove_interface,
1812 .config = wl1271_op_config,
1813/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001814 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001815 .configure_filter = wl1271_op_configure_filter,
1816 .tx = wl1271_op_tx,
1817 .set_key = wl1271_op_set_key,
1818 .hw_scan = wl1271_op_hw_scan,
1819 .bss_info_changed = wl1271_op_bss_info_changed,
1820 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001821 .conf_tx = wl1271_op_conf_tx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822};
1823
1824static int wl1271_register_hw(struct wl1271 *wl)
1825{
1826 int ret;
1827
1828 if (wl->mac80211_registered)
1829 return 0;
1830
1831 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1832
1833 ret = ieee80211_register_hw(wl->hw);
1834 if (ret < 0) {
1835 wl1271_error("unable to register mac80211 hw: %d", ret);
1836 return ret;
1837 }
1838
1839 wl->mac80211_registered = true;
1840
1841 wl1271_notice("loaded");
1842
1843 return 0;
1844}
1845
1846static int wl1271_init_ieee80211(struct wl1271 *wl)
1847{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001848 /* The tx descriptor buffer and the TKIP space. */
1849 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1850 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851
1852 /* unit us */
1853 /* FIXME: find a proper value */
1854 wl->hw->channel_change_time = 10000;
1855
1856 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001857 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001858 IEEE80211_HW_BEACON_FILTER |
1859 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001861 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1862 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 wl->hw->wiphy->max_scan_ssids = 1;
1864 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1865
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001866 if (wl1271_11a_enabled())
1867 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1868
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001869 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1870
1871 return 0;
1872}
1873
1874static void wl1271_device_release(struct device *dev)
1875{
1876
1877}
1878
1879static struct platform_device wl1271_device = {
1880 .name = "wl1271",
1881 .id = -1,
1882
1883 /* device model insists to have a release function */
1884 .dev = {
1885 .release = wl1271_device_release,
1886 },
1887};
1888
1889#define WL1271_DEFAULT_CHANNEL 0
1890static int __devinit wl1271_probe(struct spi_device *spi)
1891{
1892 struct wl12xx_platform_data *pdata;
1893 struct ieee80211_hw *hw;
1894 struct wl1271 *wl;
1895 int ret, i;
1896 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1897
1898 pdata = spi->dev.platform_data;
1899 if (!pdata) {
1900 wl1271_error("no platform data");
1901 return -ENODEV;
1902 }
1903
1904 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1905 if (!hw) {
1906 wl1271_error("could not alloc ieee80211_hw");
1907 return -ENOMEM;
1908 }
1909
1910 wl = hw->priv;
1911 memset(wl, 0, sizeof(*wl));
1912
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001913 INIT_LIST_HEAD(&wl->list);
1914
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915 wl->hw = hw;
1916 dev_set_drvdata(&spi->dev, wl);
1917 wl->spi = spi;
1918
1919 skb_queue_head_init(&wl->tx_queue);
1920
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001921 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001922 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924 wl->rx_counter = 0;
1925 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1926 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001927 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001929 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001930 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1931 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001932 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001933 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001934 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001936 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 wl->tx_frames[i] = NULL;
1938
1939 spin_lock_init(&wl->wl_lock);
1940
1941 /*
1942 * In case our MAC address is not correctly set,
1943 * we use a random but Nokia MAC.
1944 */
1945 memcpy(wl->mac_addr, nokia_oui, 3);
1946 get_random_bytes(wl->mac_addr + 3, 3);
1947
1948 wl->state = WL1271_STATE_OFF;
1949 mutex_init(&wl->mutex);
1950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 /* This is the only SPI value that we need to set here, the rest
1952 * comes from the board-peripherals file */
1953 spi->bits_per_word = 32;
1954
1955 ret = spi_setup(spi);
1956 if (ret < 0) {
1957 wl1271_error("spi_setup failed");
1958 goto out_free;
1959 }
1960
1961 wl->set_power = pdata->set_power;
1962 if (!wl->set_power) {
1963 wl1271_error("set power function missing in platform data");
1964 ret = -ENODEV;
1965 goto out_free;
1966 }
1967
1968 wl->irq = spi->irq;
1969 if (wl->irq < 0) {
1970 wl1271_error("irq missing in platform data");
1971 ret = -ENODEV;
1972 goto out_free;
1973 }
1974
1975 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1976 if (ret < 0) {
1977 wl1271_error("request_irq() failed: %d", ret);
1978 goto out_free;
1979 }
1980
1981 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1982
1983 disable_irq(wl->irq);
1984
1985 ret = platform_device_register(&wl1271_device);
1986 if (ret) {
1987 wl1271_error("couldn't register platform device");
1988 goto out_irq;
1989 }
1990 dev_set_drvdata(&wl1271_device.dev, wl);
1991
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001992 /* Apply default driver configuration. */
1993 wl1271_conf_init(wl);
1994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995 ret = wl1271_init_ieee80211(wl);
1996 if (ret)
1997 goto out_platform;
1998
1999 ret = wl1271_register_hw(wl);
2000 if (ret)
2001 goto out_platform;
2002
2003 wl1271_debugfs_init(wl);
2004
2005 wl1271_notice("initialized");
2006
2007 return 0;
2008
2009 out_platform:
2010 platform_device_unregister(&wl1271_device);
2011
2012 out_irq:
2013 free_irq(wl->irq, wl);
2014
2015 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 ieee80211_free_hw(hw);
2017
2018 return ret;
2019}
2020
2021static int __devexit wl1271_remove(struct spi_device *spi)
2022{
2023 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2024
2025 ieee80211_unregister_hw(wl->hw);
2026
2027 wl1271_debugfs_exit(wl);
2028 platform_device_unregister(&wl1271_device);
2029 free_irq(wl->irq, wl);
2030 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002031 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 wl->fw = NULL;
2033 kfree(wl->nvs);
2034 wl->nvs = NULL;
2035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 kfree(wl->fw_status);
2037 kfree(wl->tx_res_if);
2038
2039 ieee80211_free_hw(wl->hw);
2040
2041 return 0;
2042}
2043
2044
2045static struct spi_driver wl1271_spi_driver = {
2046 .driver = {
2047 .name = "wl1271",
2048 .bus = &spi_bus_type,
2049 .owner = THIS_MODULE,
2050 },
2051
2052 .probe = wl1271_probe,
2053 .remove = __devexit_p(wl1271_remove),
2054};
2055
2056static int __init wl1271_init(void)
2057{
2058 int ret;
2059
2060 ret = spi_register_driver(&wl1271_spi_driver);
2061 if (ret < 0) {
2062 wl1271_error("failed to register spi driver: %d", ret);
2063 goto out;
2064 }
2065
2066out:
2067 return ret;
2068}
2069
2070static void __exit wl1271_exit(void)
2071{
2072 spi_unregister_driver(&wl1271_spi_driver);
2073
2074 wl1271_notice("unloaded");
2075}
2076
2077module_init(wl1271_init);
2078module_exit(wl1271_exit);
2079
2080MODULE_LICENSE("GPL");
2081MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002082MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002083MODULE_FIRMWARE(WL1271_FW_NAME);