blob: 3d2e999ef15af8c1a7f7aaa29cbd2567a1ba49ee [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>
35
36#include "wl1271.h"
37#include "wl12xx_80211.h"
38#include "wl1271_reg.h"
39#include "wl1271_spi.h"
40#include "wl1271_event.h"
41#include "wl1271_tx.h"
42#include "wl1271_rx.h"
43#include "wl1271_ps.h"
44#include "wl1271_init.h"
45#include "wl1271_debugfs.h"
46#include "wl1271_cmd.h"
47#include "wl1271_boot.h"
48
Juuso Oikarinen8a080482009-10-13 12:47:44 +030049static struct conf_drv_settings default_conf = {
50 .sg = {
51 .per_threshold = 7500,
52 .max_scan_compensation_time = 120000,
53 .nfs_sample_interval = 400,
54 .load_ratio = 50,
55 .auto_ps_mode = 0,
56 .probe_req_compensation = 170,
57 .scan_window_compensation = 50,
58 .antenna_config = 0,
59 .beacon_miss_threshold = 60,
60 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
61 .rate_adaptation_snr = 0
62 },
63 .rx = {
64 .rx_msdu_life_time = 512000,
65 .packet_detection_threshold = 0,
66 .ps_poll_timeout = 15,
67 .upsd_timeout = 15,
68 .rts_threshold = 2347,
69 .rx_cca_threshold = 0xFFEF,
70 .irq_blk_threshold = 0,
71 .irq_pkt_threshold = USHORT_MAX,
72 .irq_timeout = 5,
73 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
74 },
75 .tx = {
76 .tx_energy_detection = 0,
77 .rc_conf = {
78 .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
79 .short_retry_limit = 10,
80 .long_retry_limit = 10,
81 .aflags = 0
82 },
83 .ac_conf_count = 4,
84 .ac_conf = {
85 [0] = {
86 .ac = CONF_TX_AC_BE,
87 .cw_min = 15,
88 .cw_max = 63,
89 .aifsn = 3,
90 .tx_op_limit = 0,
91 },
92 [1] = {
93 .ac = CONF_TX_AC_BK,
94 .cw_min = 15,
95 .cw_max = 63,
96 .aifsn = 7,
97 .tx_op_limit = 0,
98 },
99 [2] = {
100 .ac = CONF_TX_AC_VI,
101 .cw_min = 15,
102 .cw_max = 63,
103 .aifsn = CONF_TX_AIFS_PIFS,
104 .tx_op_limit = 3008,
105 },
106 [3] = {
107 .ac = CONF_TX_AC_VO,
108 .cw_min = 15,
109 .cw_max = 63,
110 .aifsn = CONF_TX_AIFS_PIFS,
111 .tx_op_limit = 1504,
112 },
113 },
114 .tid_conf_count = 7,
115 .tid_conf = {
116 [0] = {
117 .queue_id = 0,
118 .channel_type = CONF_CHANNEL_TYPE_DCF,
119 .tsid = CONF_TX_AC_BE,
120 .ps_scheme = CONF_PS_SCHEME_LEGACY,
121 .ack_policy = CONF_ACK_POLICY_LEGACY,
122 .apsd_conf = {0, 0},
123 },
124 [1] = {
125 .queue_id = 1,
126 .channel_type = CONF_CHANNEL_TYPE_DCF,
127 .tsid = CONF_TX_AC_BE,
128 .ps_scheme = CONF_PS_SCHEME_LEGACY,
129 .ack_policy = CONF_ACK_POLICY_LEGACY,
130 .apsd_conf = {0, 0},
131 },
132 [2] = {
133 .queue_id = 2,
134 .channel_type = CONF_CHANNEL_TYPE_DCF,
135 .tsid = CONF_TX_AC_BE,
136 .ps_scheme = CONF_PS_SCHEME_LEGACY,
137 .ack_policy = CONF_ACK_POLICY_LEGACY,
138 .apsd_conf = {0, 0},
139 },
140 [3] = {
141 .queue_id = 3,
142 .channel_type = CONF_CHANNEL_TYPE_DCF,
143 .tsid = CONF_TX_AC_BE,
144 .ps_scheme = CONF_PS_SCHEME_LEGACY,
145 .ack_policy = CONF_ACK_POLICY_LEGACY,
146 .apsd_conf = {0, 0},
147 },
148 [4] = {
149 .queue_id = 4,
150 .channel_type = CONF_CHANNEL_TYPE_DCF,
151 .tsid = CONF_TX_AC_BE,
152 .ps_scheme = CONF_PS_SCHEME_LEGACY,
153 .ack_policy = CONF_ACK_POLICY_LEGACY,
154 .apsd_conf = {0, 0},
155 },
156 [5] = {
157 .queue_id = 5,
158 .channel_type = CONF_CHANNEL_TYPE_DCF,
159 .tsid = CONF_TX_AC_BE,
160 .ps_scheme = CONF_PS_SCHEME_LEGACY,
161 .ack_policy = CONF_ACK_POLICY_LEGACY,
162 .apsd_conf = {0, 0},
163 },
164 [6] = {
165 .queue_id = 6,
166 .channel_type = CONF_CHANNEL_TYPE_DCF,
167 .tsid = CONF_TX_AC_BE,
168 .ps_scheme = CONF_PS_SCHEME_LEGACY,
169 .ack_policy = CONF_ACK_POLICY_LEGACY,
170 .apsd_conf = {0, 0},
171 }
172 },
173 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
174 .tx_compl_timeout = 5,
175 .tx_compl_threshold = 5
176 },
177 .conn = {
178 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
179 .listen_interval = 0,
180 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
181 .bcn_filt_ie_count = 1,
182 .bcn_filt_ie = {
183 [0] = {
184 .ie = WLAN_EID_CHANNEL_SWITCH,
185 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
186 }
187 },
188 .synch_fail_thold = 5,
189 .bss_lose_timeout = 100,
190 .beacon_rx_timeout = 10000,
191 .broadcast_timeout = 20000,
192 .rx_broadcast_in_ps = 1,
193 .ps_poll_threshold = 4,
194 .sig_trigger_count = 2,
195 .sig_trigger = {
196 [0] = {
197 .threshold = -75,
198 .pacing = 500,
199 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
200 .type = CONF_TRIG_EVENT_TYPE_EDGE,
201 .direction = CONF_TRIG_EVENT_DIR_LOW,
202 .hysteresis = 2,
203 .index = 0,
204 .enable = 1
205 },
206 [1] = {
207 .threshold = -75,
208 .pacing = 500,
209 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
210 .type = CONF_TRIG_EVENT_TYPE_EDGE,
211 .direction = CONF_TRIG_EVENT_DIR_HIGH,
212 .hysteresis = 2,
213 .index = 1,
214 .enable = 1
215 }
216 },
217 .sig_weights = {
218 .rssi_bcn_avg_weight = 10,
219 .rssi_pkt_avg_weight = 10,
220 .snr_bcn_avg_weight = 10,
221 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300222 },
223 .bet_enable = CONF_BET_MODE_ENABLE,
224 .bet_max_consecutive = 100
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 },
226 .init = {
227 .sr_err_tbl = {
228 [0] = {
229 .len = 7,
230 .upper_limit = 0x03,
231 .values = {
232 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
233 0x00 }
234 },
235 [1] = {
236 .len = 7,
237 .upper_limit = 0x03,
238 .values = {
239 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
240 0x00 }
241 },
242 [2] = {
243 .len = 7,
244 .upper_limit = 0x03,
245 .values = {
246 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
247 0x00 }
248 }
249 },
250 .sr_enable = 1,
251 .genparam = {
252 /*
253 * FIXME: The correct value CONF_REF_CLK_38_4_E
254 * causes the firmware to crash on boot.
255 * The value 5 apparently is an
256 * unnoficial XTAL configuration of the
257 * same frequency, which appears to work.
258 */
259 .ref_clk = 5,
260 .settling_time = 5,
261 .clk_valid_on_wakeup = 0,
262 .dc2dcmode = 0,
263 .single_dual_band = 0,
264 .tx_bip_fem_autodetect = 0,
265 .tx_bip_fem_manufacturer = 1,
266 .settings = 1,
267 },
268 .radioparam = {
269 /* FIXME: 5GHz values unset! */
270 .rx_trace_loss = 10,
271 .tx_trace_loss = 10,
272 .rx_rssi_and_proc_compens = {
273 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
274 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
275 0x00, 0x0a, 0x14 },
276 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
277 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
278 .rx_rssi_and_proc_compens_5 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 0x00, 0x00, 0x00 },
282 .tx_ref_pd_voltage = 0x24e,
283 .tx_ref_power = 0x78,
284 .tx_offset_db = 0x0,
285 .tx_rate_limits_normal = {
286 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
287 .tx_rate_limits_degraded = {
288 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
289 .tx_channel_limits_11b = {
290 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
291 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
292 0x22, 0x50 },
293 .tx_channel_limits_ofdm = {
294 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
295 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
296 0x20, 0x50 },
297 .tx_pdv_rate_offsets = {
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
299 .tx_ibias = {
300 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
301 .rx_fem_insertion_loss = 0x14,
302 .tx_ref_pd_voltage_5 = { 0, 0, 0, 0, 0, 0, 0 },
303 .tx_ref_power_5 = { 0, 0, 0, 0, 0, 0, 0 },
304 .tx_offset_db_5 = {0, 0, 0, 0, 0, 0, 0 },
305 .tx_rate_limits_normal_5 = {
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
307 .tx_rate_limits_degraded_5 = {
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
309 .tx_channel_limits_ofdm_5 = {
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00},
316 .tx_pdv_rate_offsets_5 = {
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
318 .tx_ibias_5 = {
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
320 .rx_fem_insertion_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }
321 }
322 }
323};
324
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300325static void wl1271_conf_init(struct wl1271 *wl)
326{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300327
328 /*
329 * This function applies the default configuration to the driver. This
330 * function is invoked upon driver load (spi probe.)
331 *
332 * The configuration is stored in a run-time structure in order to
333 * facilitate for run-time adjustment of any of the parameters. Making
334 * changes to the configuration structure will apply the new values on
335 * the next interface up (wl1271_op_start.)
336 */
337
338 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300339 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340}
341
342
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300343static int wl1271_plt_init(struct wl1271 *wl)
344{
345 int ret;
346
347 ret = wl1271_acx_init_mem_config(wl);
348 if (ret < 0)
349 return ret;
350
351 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
352 if (ret < 0)
353 return ret;
354
355 return 0;
356}
357
358static void wl1271_disable_interrupts(struct wl1271 *wl)
359{
360 disable_irq(wl->irq);
361}
362
363static void wl1271_power_off(struct wl1271 *wl)
364{
365 wl->set_power(false);
366}
367
368static void wl1271_power_on(struct wl1271 *wl)
369{
370 wl->set_power(true);
371}
372
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300373static void wl1271_fw_status(struct wl1271 *wl,
374 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300375{
376 u32 total = 0;
377 int i;
378
Juuso Oikarinen74621412009-10-12 15:08:54 +0300379 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
380 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381
382 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
383 "drv_rx_counter = %d, tx_results_counter = %d)",
384 status->intr,
385 status->fw_rx_counter,
386 status->drv_rx_counter,
387 status->tx_results_counter);
388
389 /* update number of available TX blocks */
390 for (i = 0; i < NUM_TX_QUEUES; i++) {
391 u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
392 wl->tx_blocks_freed[i] = status->tx_released_blks[i];
393 wl->tx_blocks_available += cnt;
394 total += cnt;
395 }
396
397 /* if more blocks are available now, schedule some tx work */
398 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300399 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300400
401 /* update the host-chipset time offset */
402 wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
403}
404
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405static void wl1271_irq_work(struct work_struct *work)
406{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300408 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409 struct wl1271 *wl =
410 container_of(work, struct wl1271, irq_work);
411
412 mutex_lock(&wl->mutex);
413
414 wl1271_debug(DEBUG_IRQ, "IRQ work");
415
416 if (wl->state == WL1271_STATE_OFF)
417 goto out;
418
419 ret = wl1271_ps_elp_wakeup(wl, true);
420 if (ret < 0)
421 goto out;
422
Juuso Oikarinen74621412009-10-12 15:08:54 +0300423 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300425 wl1271_fw_status(wl, wl->fw_status);
426 intr = wl->fw_status->intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427 if (!intr) {
428 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
429 goto out_sleep;
430 }
431
432 intr &= WL1271_INTR_MASK;
433
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300434 if (intr & (WL1271_ACX_INTR_EVENT_A |
435 WL1271_ACX_INTR_EVENT_B)) {
436 wl1271_debug(DEBUG_IRQ,
437 "WL1271_ACX_INTR_EVENT (0x%x)", intr);
438 if (intr & WL1271_ACX_INTR_EVENT_A)
439 wl1271_event_handle(wl, 0);
440 else
441 wl1271_event_handle(wl, 1);
442 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300443
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300444 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
445 wl1271_debug(DEBUG_IRQ,
446 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300448 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
449 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300451 if (intr & WL1271_ACX_INTR_DATA) {
452 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
453 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300455 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457 /* check for tx results */
458 if (tx_res_cnt)
459 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300461 wl1271_rx(wl, wl->fw_status);
462 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463
464out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300465 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300466 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300467 wl1271_ps_elp_sleep(wl);
468
469out:
470 mutex_unlock(&wl->mutex);
471}
472
473static irqreturn_t wl1271_irq(int irq, void *cookie)
474{
475 struct wl1271 *wl;
476 unsigned long flags;
477
478 wl1271_debug(DEBUG_IRQ, "IRQ");
479
480 wl = cookie;
481
482 /* complete the ELP completion */
483 spin_lock_irqsave(&wl->wl_lock, flags);
484 if (wl->elp_compl) {
485 complete(wl->elp_compl);
486 wl->elp_compl = NULL;
487 }
488
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300489 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300490 spin_unlock_irqrestore(&wl->wl_lock, flags);
491
492 return IRQ_HANDLED;
493}
494
495static int wl1271_fetch_firmware(struct wl1271 *wl)
496{
497 const struct firmware *fw;
498 int ret;
499
500 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
501
502 if (ret < 0) {
503 wl1271_error("could not get firmware: %d", ret);
504 return ret;
505 }
506
507 if (fw->size % 4) {
508 wl1271_error("firmware size is not multiple of 32 bits: %zu",
509 fw->size);
510 ret = -EILSEQ;
511 goto out;
512 }
513
514 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300515 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300516
517 if (!wl->fw) {
518 wl1271_error("could not allocate memory for the firmware");
519 ret = -ENOMEM;
520 goto out;
521 }
522
523 memcpy(wl->fw, fw->data, wl->fw_len);
524
525 ret = 0;
526
527out:
528 release_firmware(fw);
529
530 return ret;
531}
532
533static int wl1271_fetch_nvs(struct wl1271 *wl)
534{
535 const struct firmware *fw;
536 int ret;
537
538 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
539
540 if (ret < 0) {
541 wl1271_error("could not get nvs file: %d", ret);
542 return ret;
543 }
544
545 if (fw->size % 4) {
546 wl1271_error("nvs size is not multiple of 32 bits: %zu",
547 fw->size);
548 ret = -EILSEQ;
549 goto out;
550 }
551
552 wl->nvs_len = fw->size;
553 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
554
555 if (!wl->nvs) {
556 wl1271_error("could not allocate memory for the nvs file");
557 ret = -ENOMEM;
558 goto out;
559 }
560
561 memcpy(wl->nvs, fw->data, wl->nvs_len);
562
563 ret = 0;
564
565out:
566 release_firmware(fw);
567
568 return ret;
569}
570
571static void wl1271_fw_wakeup(struct wl1271 *wl)
572{
573 u32 elp_reg;
574
575 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300576 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300577}
578
579static int wl1271_setup(struct wl1271 *wl)
580{
581 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
582 if (!wl->fw_status)
583 return -ENOMEM;
584
585 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
586 if (!wl->tx_res_if) {
587 kfree(wl->fw_status);
588 return -ENOMEM;
589 }
590
591 INIT_WORK(&wl->irq_work, wl1271_irq_work);
592 INIT_WORK(&wl->tx_work, wl1271_tx_work);
593 return 0;
594}
595
596static int wl1271_chip_wakeup(struct wl1271 *wl)
597{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300598 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300599 int ret = 0;
600
601 wl1271_power_on(wl);
602 msleep(WL1271_POWER_ON_SLEEP);
603 wl1271_spi_reset(wl);
604 wl1271_spi_init(wl);
605
606 /* We don't need a real memory partition here, because we only want
607 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300608 memset(&partition, 0, sizeof(partition));
609 partition.reg.start = REGISTERS_BASE;
610 partition.reg.size = REGISTERS_DOWN_SIZE;
611 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300612
613 /* ELP module wake up */
614 wl1271_fw_wakeup(wl);
615
616 /* whal_FwCtrl_BootSm() */
617
618 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300619 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300620
621 /* 1. check if chip id is valid */
622
623 switch (wl->chip.id) {
624 case CHIP_ID_1271_PG10:
625 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
626 wl->chip.id);
627
628 ret = wl1271_setup(wl);
629 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300630 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300631 break;
632 case CHIP_ID_1271_PG20:
633 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
634 wl->chip.id);
635
636 ret = wl1271_setup(wl);
637 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300638 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 break;
640 default:
641 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
642 ret = -ENODEV;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300643 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300644 }
645
646 if (wl->fw == NULL) {
647 ret = wl1271_fetch_firmware(wl);
648 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300649 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650 }
651
652 /* No NVS from netlink, try to get it from the filesystem */
653 if (wl->nvs == NULL) {
654 ret = wl1271_fetch_nvs(wl);
655 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300656 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657 }
658
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300659 goto out;
660
661out_power_off:
662 wl1271_power_off(wl);
663
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664out:
665 return ret;
666}
667
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300668struct wl1271_filter_params {
669 unsigned int filters;
670 unsigned int changed;
671 int mc_list_length;
672 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
673};
674
675#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
676 FIF_ALLMULTI | \
677 FIF_FCSFAIL | \
678 FIF_BCN_PRBRESP_PROMISC | \
679 FIF_CONTROL | \
680 FIF_OTHER_BSS)
681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682static void wl1271_filter_work(struct work_struct *work)
683{
684 struct wl1271 *wl =
685 container_of(work, struct wl1271, filter_work);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300686 struct wl1271_filter_params *fp;
687 unsigned long flags;
688 bool enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 int ret;
690
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300691 /* first, get the filter parameters */
692 spin_lock_irqsave(&wl->wl_lock, flags);
693 fp = wl->filter_params;
694 wl->filter_params = NULL;
695 spin_unlock_irqrestore(&wl->wl_lock, flags);
696
697 if (!fp)
698 return;
699
700 /* then, lock the mutex without risk of lock-up */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701 mutex_lock(&wl->mutex);
702
703 if (wl->state == WL1271_STATE_OFF)
704 goto out;
705
706 ret = wl1271_ps_elp_wakeup(wl, false);
707 if (ret < 0)
708 goto out;
709
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300710 /* configure the mc filter regardless of the changed flags */
711 if (fp->filters & FIF_ALLMULTI)
712 enabled = false;
713
714 ret = wl1271_acx_group_address_tbl(wl, enabled,
715 fp->mc_list, fp->mc_list_length);
716 if (ret < 0)
717 goto out_sleep;
718
719 /* determine, whether supported filter values have changed */
720 if (fp->changed == 0)
721 goto out;
722
723 /* apply configured filters */
Luciano Coelho0535d9f2009-10-12 15:08:56 +0300724 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725 if (ret < 0)
726 goto out_sleep;
727
728out_sleep:
729 wl1271_ps_elp_sleep(wl);
730
731out:
732 mutex_unlock(&wl->mutex);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300733 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734}
735
736int wl1271_plt_start(struct wl1271 *wl)
737{
738 int ret;
739
740 mutex_lock(&wl->mutex);
741
742 wl1271_notice("power up");
743
744 if (wl->state != WL1271_STATE_OFF) {
745 wl1271_error("cannot go into PLT state because not "
746 "in off state: %d", wl->state);
747 ret = -EBUSY;
748 goto out;
749 }
750
751 wl->state = WL1271_STATE_PLT;
752
753 ret = wl1271_chip_wakeup(wl);
754 if (ret < 0)
755 goto out;
756
757 ret = wl1271_boot(wl);
758 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300759 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760
761 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
762
763 ret = wl1271_plt_init(wl);
764 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300765 goto out_irq_disable;
766
767 goto out;
768
769out_irq_disable:
770 wl1271_disable_interrupts(wl);
771
772out_power_off:
773 wl1271_power_off(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774
775out:
776 mutex_unlock(&wl->mutex);
777
778 return ret;
779}
780
781int wl1271_plt_stop(struct wl1271 *wl)
782{
783 int ret = 0;
784
785 mutex_lock(&wl->mutex);
786
787 wl1271_notice("power down");
788
789 if (wl->state != WL1271_STATE_PLT) {
790 wl1271_error("cannot power down because not in PLT "
791 "state: %d", wl->state);
792 ret = -EBUSY;
793 goto out;
794 }
795
796 wl1271_disable_interrupts(wl);
797 wl1271_power_off(wl);
798
799 wl->state = WL1271_STATE_OFF;
800
801out:
802 mutex_unlock(&wl->mutex);
803
804 return ret;
805}
806
807
808static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
809{
810 struct wl1271 *wl = hw->priv;
811
812 skb_queue_tail(&wl->tx_queue, skb);
813
814 /*
815 * The chip specific setup must run before the first TX packet -
816 * before that, the tx_work will not be initialized!
817 */
818
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300819 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820
821 /*
822 * The workqueue is slow to process the tx_queue and we need stop
823 * the queue here, otherwise the queue will get too long.
824 */
825 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
826 ieee80211_stop_queues(wl->hw);
827
828 /*
829 * FIXME: this is racy, the variable is not properly
830 * protected. Maybe fix this by removing the stupid
831 * variable altogether and checking the real queue state?
832 */
833 wl->tx_queue_stopped = true;
834 }
835
836 return NETDEV_TX_OK;
837}
838
839static int wl1271_op_start(struct ieee80211_hw *hw)
840{
841 struct wl1271 *wl = hw->priv;
842 int ret = 0;
843
844 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
845
846 mutex_lock(&wl->mutex);
847
848 if (wl->state != WL1271_STATE_OFF) {
849 wl1271_error("cannot start because not in off state: %d",
850 wl->state);
851 ret = -EBUSY;
852 goto out;
853 }
854
855 ret = wl1271_chip_wakeup(wl);
856 if (ret < 0)
857 goto out;
858
859 ret = wl1271_boot(wl);
860 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300861 goto out_power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862
863 ret = wl1271_hw_init(wl);
864 if (ret < 0)
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300865 goto out_irq_disable;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866
867 wl->state = WL1271_STATE_ON;
868
869 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
870
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300871 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300873out_irq_disable:
874 wl1271_disable_interrupts(wl);
875
876out_power_off:
877 wl1271_power_off(wl);
878
879out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880 mutex_unlock(&wl->mutex);
881
882 return ret;
883}
884
885static void wl1271_op_stop(struct ieee80211_hw *hw)
886{
887 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300888 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889 int i;
890
891 wl1271_info("down");
892
893 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
894
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300895 /* complete/cancel ongoing work */
896 cancel_work_sync(&wl->filter_work);
897 spin_lock_irqsave(&wl->wl_lock, flags);
898 kfree(wl->filter_params);
899 wl->filter_params = NULL;
900 spin_unlock_irqrestore(&wl->wl_lock, flags);
901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 mutex_lock(&wl->mutex);
903
904 WARN_ON(wl->state != WL1271_STATE_ON);
905
906 if (wl->scanning) {
907 mutex_unlock(&wl->mutex);
908 ieee80211_scan_completed(wl->hw, true);
909 mutex_lock(&wl->mutex);
910 wl->scanning = false;
911 }
912
913 wl->state = WL1271_STATE_OFF;
914
915 wl1271_disable_interrupts(wl);
916
917 mutex_unlock(&wl->mutex);
918
919 cancel_work_sync(&wl->irq_work);
920 cancel_work_sync(&wl->tx_work);
921 cancel_work_sync(&wl->filter_work);
922
923 mutex_lock(&wl->mutex);
924
925 /* let's notify MAC80211 about the remaining pending TX frames */
926 wl1271_tx_flush(wl);
927 wl1271_power_off(wl);
928
929 memset(wl->bssid, 0, ETH_ALEN);
930 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
931 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300933 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934
935 wl->rx_counter = 0;
936 wl->elp = false;
937 wl->psm = 0;
938 wl->tx_queue_stopped = false;
939 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
940 wl->tx_blocks_available = 0;
941 wl->tx_results_count = 0;
942 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300943 wl->tx_security_last_seq = 0;
944 wl->tx_security_seq_16 = 0;
945 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 wl->time_offset = 0;
947 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300948 wl->joined = false;
949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 for (i = 0; i < NUM_TX_QUEUES; i++)
951 wl->tx_blocks_freed[i] = 0;
952
953 wl1271_debugfs_reset(wl);
954 mutex_unlock(&wl->mutex);
955}
956
957static int wl1271_op_add_interface(struct ieee80211_hw *hw,
958 struct ieee80211_if_init_conf *conf)
959{
960 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 int ret = 0;
962
John W. Linvillee5539bc2009-08-18 10:50:34 -0400963 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
964 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965
966 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300967 if (wl->vif) {
968 ret = -EBUSY;
969 goto out;
970 }
971
972 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973
974 switch (conf->type) {
975 case NL80211_IFTYPE_STATION:
976 wl->bss_type = BSS_TYPE_STA_BSS;
977 break;
978 case NL80211_IFTYPE_ADHOC:
979 wl->bss_type = BSS_TYPE_IBSS;
980 break;
981 default:
982 ret = -EOPNOTSUPP;
983 goto out;
984 }
985
986 /* FIXME: what if conf->mac_addr changes? */
987
988out:
989 mutex_unlock(&wl->mutex);
990 return ret;
991}
992
993static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
994 struct ieee80211_if_init_conf *conf)
995{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300996 struct wl1271 *wl = hw->priv;
997
998 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001000 wl->vif = NULL;
1001 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002}
1003
1004#if 0
1005static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1006 struct ieee80211_vif *vif,
1007 struct ieee80211_if_conf *conf)
1008{
1009 struct wl1271 *wl = hw->priv;
1010 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 int ret;
1012
David S. Miller32646902009-09-17 10:18:30 -07001013 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1014 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1016 conf->ssid_len);
1017
1018 mutex_lock(&wl->mutex);
1019
1020 ret = wl1271_ps_elp_wakeup(wl, false);
1021 if (ret < 0)
1022 goto out;
1023
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001024 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1025 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1026
1027 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1028
1029 ret = wl1271_cmd_join(wl);
1030 if (ret < 0)
1031 goto out_sleep;
1032 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033
1034 ret = wl1271_cmd_build_null_data(wl);
1035 if (ret < 0)
1036 goto out_sleep;
1037
1038 wl->ssid_len = conf->ssid_len;
1039 if (wl->ssid_len)
1040 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 if (conf->changed & IEEE80211_IFCC_BEACON) {
1043 beacon = ieee80211_beacon_get(hw, vif);
1044 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1045 beacon->data, beacon->len);
1046
1047 if (ret < 0) {
1048 dev_kfree_skb(beacon);
1049 goto out_sleep;
1050 }
1051
1052 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1053 beacon->data, beacon->len);
1054
1055 dev_kfree_skb(beacon);
1056
1057 if (ret < 0)
1058 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059 }
1060
1061out_sleep:
1062 wl1271_ps_elp_sleep(wl);
1063
1064out:
1065 mutex_unlock(&wl->mutex);
1066
1067 return ret;
1068}
1069#endif
1070
1071static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1072{
1073 struct wl1271 *wl = hw->priv;
1074 struct ieee80211_conf *conf = &hw->conf;
1075 int channel, ret = 0;
1076
1077 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1078
1079 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1080 channel,
1081 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1082 conf->power_level);
1083
1084 mutex_lock(&wl->mutex);
1085
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001086 wl->band = conf->channel->band;
1087
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088 ret = wl1271_ps_elp_wakeup(wl, false);
1089 if (ret < 0)
1090 goto out;
1091
1092 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001093 /*
1094 * We assume that the stack will configure the right channel
1095 * before associating, so we don't need to send a join
1096 * command here. We will join the right channel when the
1097 * BSSID changes
1098 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 }
1101
1102 ret = wl1271_cmd_build_null_data(wl);
1103 if (ret < 0)
1104 goto out_sleep;
1105
1106 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1107 wl1271_info("psm enabled");
1108
1109 wl->psm_requested = true;
1110
1111 /*
1112 * We enter PSM only if we're already associated.
1113 * If we're not, we'll enter it when joining an SSID,
1114 * through the bss_info_changed() hook.
1115 */
1116 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1117 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1118 wl->psm_requested) {
1119 wl1271_info("psm disabled");
1120
1121 wl->psm_requested = false;
1122
1123 if (wl->psm)
1124 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1125 }
1126
1127 if (conf->power_level != wl->power_level) {
1128 ret = wl1271_acx_tx_power(wl, conf->power_level);
1129 if (ret < 0)
1130 goto out;
1131
1132 wl->power_level = conf->power_level;
1133 }
1134
1135out_sleep:
1136 wl1271_ps_elp_sleep(wl);
1137
1138out:
1139 mutex_unlock(&wl->mutex);
1140
1141 return ret;
1142}
1143
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001144static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1145 struct dev_addr_list *mc_list)
1146{
1147 struct wl1271 *wl = hw->priv;
1148 struct wl1271_filter_params *fp;
1149 unsigned long flags;
1150 int i;
1151
1152 /*
1153 * FIXME: we should return a hash that will be passed to
1154 * configure_filter() instead of saving everything in the context.
1155 */
1156
1157 fp = kzalloc(sizeof(*fp), GFP_KERNEL);
1158 if (!fp) {
1159 wl1271_error("Out of memory setting filters.");
1160 return 0;
1161 }
1162
1163 /* update multicast filtering parameters */
1164 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1165 mc_count = 0;
1166 fp->filters |= FIF_ALLMULTI;
1167 }
1168
1169 fp->mc_list_length = 0;
1170 for (i = 0; i < mc_count; i++) {
1171 if (mc_list->da_addrlen == ETH_ALEN) {
1172 memcpy(fp->mc_list[fp->mc_list_length],
1173 mc_list->da_addr, ETH_ALEN);
1174 fp->mc_list_length++;
1175 } else
1176 wl1271_warning("Unknown mc address length.");
1177 }
1178
Luciano Coelho0535d9f2009-10-12 15:08:56 +03001179 /* FIXME: We still need to set our filters properly */
1180
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001181 spin_lock_irqsave(&wl->wl_lock, flags);
1182 kfree(wl->filter_params);
1183 wl->filter_params = fp;
1184 spin_unlock_irqrestore(&wl->wl_lock, flags);
1185
1186 return 1;
1187}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001188
1189static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1190 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001191 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192{
1193 struct wl1271 *wl = hw->priv;
1194
1195 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1196
1197 *total &= WL1271_SUPPORTED_FILTERS;
1198 changed &= WL1271_SUPPORTED_FILTERS;
1199
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001200 if (!multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 return;
1202
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203 /*
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001204 * FIXME: for now we are still using a workqueue for filter
1205 * configuration, but with the new mac80211, this is not needed,
1206 * since configure_filter can now sleep. We now have
1207 * prepare_multicast, which needs to be atomic instead.
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208 */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001209
1210 /* store current filter config */
1211 wl->filter_params->filters = *total;
1212 wl->filter_params->changed = changed;
1213
1214 ieee80211_queue_work(wl->hw, &wl->filter_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215}
1216
1217static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1218 struct ieee80211_vif *vif,
1219 struct ieee80211_sta *sta,
1220 struct ieee80211_key_conf *key_conf)
1221{
1222 struct wl1271 *wl = hw->priv;
1223 const u8 *addr;
1224 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001225 u32 tx_seq_32 = 0;
1226 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227 u8 key_type;
1228
1229 static const u8 bcast_addr[ETH_ALEN] =
1230 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1231
1232 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1233
1234 addr = sta ? sta->addr : bcast_addr;
1235
1236 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1237 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1238 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1239 key_conf->alg, key_conf->keyidx,
1240 key_conf->keylen, key_conf->flags);
1241 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1242
1243 if (is_zero_ether_addr(addr)) {
1244 /* We dont support TX only encryption */
1245 ret = -EOPNOTSUPP;
1246 goto out;
1247 }
1248
1249 mutex_lock(&wl->mutex);
1250
1251 ret = wl1271_ps_elp_wakeup(wl, false);
1252 if (ret < 0)
1253 goto out_unlock;
1254
1255 switch (key_conf->alg) {
1256 case ALG_WEP:
1257 key_type = KEY_WEP;
1258
1259 key_conf->hw_key_idx = key_conf->keyidx;
1260 break;
1261 case ALG_TKIP:
1262 key_type = KEY_TKIP;
1263
1264 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001265 tx_seq_32 = wl->tx_security_seq_32;
1266 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267 break;
1268 case ALG_CCMP:
1269 key_type = KEY_AES;
1270
1271 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001272 tx_seq_32 = wl->tx_security_seq_32;
1273 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274 break;
1275 default:
1276 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1277
1278 ret = -EOPNOTSUPP;
1279 goto out_sleep;
1280 }
1281
1282 switch (cmd) {
1283 case SET_KEY:
1284 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1285 key_conf->keyidx, key_type,
1286 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001287 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288 if (ret < 0) {
1289 wl1271_error("Could not add or replace key");
1290 goto out_sleep;
1291 }
1292 break;
1293
1294 case DISABLE_KEY:
1295 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1296 key_conf->keyidx, key_type,
1297 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001298 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299 if (ret < 0) {
1300 wl1271_error("Could not remove key");
1301 goto out_sleep;
1302 }
1303 break;
1304
1305 default:
1306 wl1271_error("Unsupported key cmd 0x%x", cmd);
1307 ret = -EOPNOTSUPP;
1308 goto out_sleep;
1309
1310 break;
1311 }
1312
1313out_sleep:
1314 wl1271_ps_elp_sleep(wl);
1315
1316out_unlock:
1317 mutex_unlock(&wl->mutex);
1318
1319out:
1320 return ret;
1321}
1322
1323static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1324 struct cfg80211_scan_request *req)
1325{
1326 struct wl1271 *wl = hw->priv;
1327 int ret;
1328 u8 *ssid = NULL;
1329 size_t ssid_len = 0;
1330
1331 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1332
1333 if (req->n_ssids) {
1334 ssid = req->ssids[0].ssid;
1335 ssid_len = req->ssids[0].ssid_len;
1336 }
1337
1338 mutex_lock(&wl->mutex);
1339
1340 ret = wl1271_ps_elp_wakeup(wl, false);
1341 if (ret < 0)
1342 goto out;
1343
1344 ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
1345
1346 wl1271_ps_elp_sleep(wl);
1347
1348out:
1349 mutex_unlock(&wl->mutex);
1350
1351 return ret;
1352}
1353
1354static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1355{
1356 struct wl1271 *wl = hw->priv;
1357 int ret;
1358
1359 mutex_lock(&wl->mutex);
1360
1361 ret = wl1271_ps_elp_wakeup(wl, false);
1362 if (ret < 0)
1363 goto out;
1364
1365 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1366 if (ret < 0)
1367 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1368
1369 wl1271_ps_elp_sleep(wl);
1370
1371out:
1372 mutex_unlock(&wl->mutex);
1373
1374 return ret;
1375}
1376
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001377static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1378{
1379 struct ieee80211_supported_band *band;
1380 u32 enabled_rates = 0;
1381 int bit;
1382
1383 band = wl->hw->wiphy->bands[wl->band];
1384 for (bit = 0; bit < band->n_bitrates; bit++) {
1385 if (basic_rate_set & 0x1)
1386 enabled_rates |= band->bitrates[bit].hw_value;
1387 basic_rate_set >>= 1;
1388 }
1389
1390 return enabled_rates;
1391}
1392
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1394 struct ieee80211_vif *vif,
1395 struct ieee80211_bss_conf *bss_conf,
1396 u32 changed)
1397{
1398 enum wl1271_cmd_ps_mode mode;
1399 struct wl1271 *wl = hw->priv;
1400 int ret;
1401
1402 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1403
1404 mutex_lock(&wl->mutex);
1405
1406 ret = wl1271_ps_elp_wakeup(wl, false);
1407 if (ret < 0)
1408 goto out;
1409
1410 if (changed & BSS_CHANGED_ASSOC) {
1411 if (bss_conf->assoc) {
1412 wl->aid = bss_conf->aid;
1413
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001414 /*
1415 * with wl1271, we don't need to update the
1416 * beacon_int and dtim_period, because the firmware
1417 * updates it by itself when the first beacon is
1418 * received after a join.
1419 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1421 if (ret < 0)
1422 goto out_sleep;
1423
1424 ret = wl1271_acx_aid(wl, wl->aid);
1425 if (ret < 0)
1426 goto out_sleep;
1427
1428 /* If we want to go in PSM but we're not there yet */
1429 if (wl->psm_requested && !wl->psm) {
1430 mode = STATION_POWER_SAVE_MODE;
1431 ret = wl1271_ps_set_mode(wl, mode);
1432 if (ret < 0)
1433 goto out_sleep;
1434 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001435 } else {
1436 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001437 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1438 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001442
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443 if (changed & BSS_CHANGED_ERP_SLOT) {
1444 if (bss_conf->use_short_slot)
1445 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1446 else
1447 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1448 if (ret < 0) {
1449 wl1271_warning("Set slot time failed %d", ret);
1450 goto out_sleep;
1451 }
1452 }
1453
1454 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1455 if (bss_conf->use_short_preamble)
1456 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1457 else
1458 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1459 }
1460
1461 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1462 if (bss_conf->use_cts_prot)
1463 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1464 else
1465 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1466 if (ret < 0) {
1467 wl1271_warning("Set ctsprotect failed %d", ret);
1468 goto out_sleep;
1469 }
1470 }
1471
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001472 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001473 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001474 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001475
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001476 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001477 if (ret < 0) {
1478 wl1271_warning("Set rate policies failed %d", ret);
1479 goto out_sleep;
1480 }
1481 }
1482
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483out_sleep:
1484 wl1271_ps_elp_sleep(wl);
1485
1486out:
1487 mutex_unlock(&wl->mutex);
1488}
1489
1490
1491/* can't be const, mac80211 writes to this */
1492static struct ieee80211_rate wl1271_rates[] = {
1493 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001494 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1495 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001497 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1498 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1500 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001501 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1502 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1504 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001505 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1506 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1508 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001509 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1510 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001512 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1513 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001515 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1516 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001518 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1519 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001521 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1522 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001524 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1525 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001527 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1528 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001530 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1531 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532};
1533
1534/* can't be const, mac80211 writes to this */
1535static struct ieee80211_channel wl1271_channels[] = {
1536 { .hw_value = 1, .center_freq = 2412},
1537 { .hw_value = 2, .center_freq = 2417},
1538 { .hw_value = 3, .center_freq = 2422},
1539 { .hw_value = 4, .center_freq = 2427},
1540 { .hw_value = 5, .center_freq = 2432},
1541 { .hw_value = 6, .center_freq = 2437},
1542 { .hw_value = 7, .center_freq = 2442},
1543 { .hw_value = 8, .center_freq = 2447},
1544 { .hw_value = 9, .center_freq = 2452},
1545 { .hw_value = 10, .center_freq = 2457},
1546 { .hw_value = 11, .center_freq = 2462},
1547 { .hw_value = 12, .center_freq = 2467},
1548 { .hw_value = 13, .center_freq = 2472},
1549};
1550
1551/* can't be const, mac80211 writes to this */
1552static struct ieee80211_supported_band wl1271_band_2ghz = {
1553 .channels = wl1271_channels,
1554 .n_channels = ARRAY_SIZE(wl1271_channels),
1555 .bitrates = wl1271_rates,
1556 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1557};
1558
1559static const struct ieee80211_ops wl1271_ops = {
1560 .start = wl1271_op_start,
1561 .stop = wl1271_op_stop,
1562 .add_interface = wl1271_op_add_interface,
1563 .remove_interface = wl1271_op_remove_interface,
1564 .config = wl1271_op_config,
1565/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001566 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001567 .configure_filter = wl1271_op_configure_filter,
1568 .tx = wl1271_op_tx,
1569 .set_key = wl1271_op_set_key,
1570 .hw_scan = wl1271_op_hw_scan,
1571 .bss_info_changed = wl1271_op_bss_info_changed,
1572 .set_rts_threshold = wl1271_op_set_rts_threshold,
1573};
1574
1575static int wl1271_register_hw(struct wl1271 *wl)
1576{
1577 int ret;
1578
1579 if (wl->mac80211_registered)
1580 return 0;
1581
1582 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1583
1584 ret = ieee80211_register_hw(wl->hw);
1585 if (ret < 0) {
1586 wl1271_error("unable to register mac80211 hw: %d", ret);
1587 return ret;
1588 }
1589
1590 wl->mac80211_registered = true;
1591
1592 wl1271_notice("loaded");
1593
1594 return 0;
1595}
1596
1597static int wl1271_init_ieee80211(struct wl1271 *wl)
1598{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001599 /* The tx descriptor buffer and the TKIP space. */
1600 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1601 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001602
1603 /* unit us */
1604 /* FIXME: find a proper value */
1605 wl->hw->channel_change_time = 10000;
1606
1607 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001608 IEEE80211_HW_NOISE_DBM |
1609 IEEE80211_HW_BEACON_FILTER;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610
1611 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1612 wl->hw->wiphy->max_scan_ssids = 1;
1613 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1614
1615 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1616
1617 return 0;
1618}
1619
1620static void wl1271_device_release(struct device *dev)
1621{
1622
1623}
1624
1625static struct platform_device wl1271_device = {
1626 .name = "wl1271",
1627 .id = -1,
1628
1629 /* device model insists to have a release function */
1630 .dev = {
1631 .release = wl1271_device_release,
1632 },
1633};
1634
1635#define WL1271_DEFAULT_CHANNEL 0
1636static int __devinit wl1271_probe(struct spi_device *spi)
1637{
1638 struct wl12xx_platform_data *pdata;
1639 struct ieee80211_hw *hw;
1640 struct wl1271 *wl;
1641 int ret, i;
1642 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1643
1644 pdata = spi->dev.platform_data;
1645 if (!pdata) {
1646 wl1271_error("no platform data");
1647 return -ENODEV;
1648 }
1649
1650 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1651 if (!hw) {
1652 wl1271_error("could not alloc ieee80211_hw");
1653 return -ENOMEM;
1654 }
1655
1656 wl = hw->priv;
1657 memset(wl, 0, sizeof(*wl));
1658
1659 wl->hw = hw;
1660 dev_set_drvdata(&spi->dev, wl);
1661 wl->spi = spi;
1662
1663 skb_queue_head_init(&wl->tx_queue);
1664
1665 INIT_WORK(&wl->filter_work, wl1271_filter_work);
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001666 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667 wl->channel = WL1271_DEFAULT_CHANNEL;
1668 wl->scanning = false;
1669 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001670 wl->rx_counter = 0;
1671 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1672 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1673 wl->elp = false;
1674 wl->psm = 0;
1675 wl->psm_requested = false;
1676 wl->tx_queue_stopped = false;
1677 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001678 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001679 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001680 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001681 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001682
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001683 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001684 wl->tx_frames[i] = NULL;
1685
1686 spin_lock_init(&wl->wl_lock);
1687
1688 /*
1689 * In case our MAC address is not correctly set,
1690 * we use a random but Nokia MAC.
1691 */
1692 memcpy(wl->mac_addr, nokia_oui, 3);
1693 get_random_bytes(wl->mac_addr + 3, 3);
1694
1695 wl->state = WL1271_STATE_OFF;
1696 mutex_init(&wl->mutex);
1697
1698 wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
1699 if (!wl->rx_descriptor) {
1700 wl1271_error("could not allocate memory for rx descriptor");
1701 ret = -ENOMEM;
1702 goto out_free;
1703 }
1704
1705 /* This is the only SPI value that we need to set here, the rest
1706 * comes from the board-peripherals file */
1707 spi->bits_per_word = 32;
1708
1709 ret = spi_setup(spi);
1710 if (ret < 0) {
1711 wl1271_error("spi_setup failed");
1712 goto out_free;
1713 }
1714
1715 wl->set_power = pdata->set_power;
1716 if (!wl->set_power) {
1717 wl1271_error("set power function missing in platform data");
1718 ret = -ENODEV;
1719 goto out_free;
1720 }
1721
1722 wl->irq = spi->irq;
1723 if (wl->irq < 0) {
1724 wl1271_error("irq missing in platform data");
1725 ret = -ENODEV;
1726 goto out_free;
1727 }
1728
1729 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1730 if (ret < 0) {
1731 wl1271_error("request_irq() failed: %d", ret);
1732 goto out_free;
1733 }
1734
1735 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1736
1737 disable_irq(wl->irq);
1738
1739 ret = platform_device_register(&wl1271_device);
1740 if (ret) {
1741 wl1271_error("couldn't register platform device");
1742 goto out_irq;
1743 }
1744 dev_set_drvdata(&wl1271_device.dev, wl);
1745
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001746 /* Apply default driver configuration. */
1747 wl1271_conf_init(wl);
1748
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001749 ret = wl1271_init_ieee80211(wl);
1750 if (ret)
1751 goto out_platform;
1752
1753 ret = wl1271_register_hw(wl);
1754 if (ret)
1755 goto out_platform;
1756
1757 wl1271_debugfs_init(wl);
1758
1759 wl1271_notice("initialized");
1760
1761 return 0;
1762
1763 out_platform:
1764 platform_device_unregister(&wl1271_device);
1765
1766 out_irq:
1767 free_irq(wl->irq, wl);
1768
1769 out_free:
1770 kfree(wl->rx_descriptor);
1771 wl->rx_descriptor = NULL;
1772
1773 ieee80211_free_hw(hw);
1774
1775 return ret;
1776}
1777
1778static int __devexit wl1271_remove(struct spi_device *spi)
1779{
1780 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1781
1782 ieee80211_unregister_hw(wl->hw);
1783
1784 wl1271_debugfs_exit(wl);
1785 platform_device_unregister(&wl1271_device);
1786 free_irq(wl->irq, wl);
1787 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001788 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001789 wl->fw = NULL;
1790 kfree(wl->nvs);
1791 wl->nvs = NULL;
1792
1793 kfree(wl->rx_descriptor);
1794 wl->rx_descriptor = NULL;
1795
1796 kfree(wl->fw_status);
1797 kfree(wl->tx_res_if);
1798
1799 ieee80211_free_hw(wl->hw);
1800
1801 return 0;
1802}
1803
1804
1805static struct spi_driver wl1271_spi_driver = {
1806 .driver = {
1807 .name = "wl1271",
1808 .bus = &spi_bus_type,
1809 .owner = THIS_MODULE,
1810 },
1811
1812 .probe = wl1271_probe,
1813 .remove = __devexit_p(wl1271_remove),
1814};
1815
1816static int __init wl1271_init(void)
1817{
1818 int ret;
1819
1820 ret = spi_register_driver(&wl1271_spi_driver);
1821 if (ret < 0) {
1822 wl1271_error("failed to register spi driver: %d", ret);
1823 goto out;
1824 }
1825
1826out:
1827 return ret;
1828}
1829
1830static void __exit wl1271_exit(void)
1831{
1832 spi_unregister_driver(&wl1271_spi_driver);
1833
1834 wl1271_notice("unloaded");
1835}
1836
1837module_init(wl1271_init);
1838module_exit(wl1271_exit);
1839
1840MODULE_LICENSE("GPL");
1841MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001842MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");