blob: eba38dff871bf30b499b31439fb356ed7c8741ca [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
222 }
223 },
224 .init = {
225 .sr_err_tbl = {
226 [0] = {
227 .len = 7,
228 .upper_limit = 0x03,
229 .values = {
230 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
231 0x00 }
232 },
233 [1] = {
234 .len = 7,
235 .upper_limit = 0x03,
236 .values = {
237 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
238 0x00 }
239 },
240 [2] = {
241 .len = 7,
242 .upper_limit = 0x03,
243 .values = {
244 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
245 0x00 }
246 }
247 },
248 .sr_enable = 1,
249 .genparam = {
250 /*
251 * FIXME: The correct value CONF_REF_CLK_38_4_E
252 * causes the firmware to crash on boot.
253 * The value 5 apparently is an
254 * unnoficial XTAL configuration of the
255 * same frequency, which appears to work.
256 */
257 .ref_clk = 5,
258 .settling_time = 5,
259 .clk_valid_on_wakeup = 0,
260 .dc2dcmode = 0,
261 .single_dual_band = 0,
262 .tx_bip_fem_autodetect = 0,
263 .tx_bip_fem_manufacturer = 1,
264 .settings = 1,
265 },
266 .radioparam = {
267 /* FIXME: 5GHz values unset! */
268 .rx_trace_loss = 10,
269 .tx_trace_loss = 10,
270 .rx_rssi_and_proc_compens = {
271 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
272 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
273 0x00, 0x0a, 0x14 },
274 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
275 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
276 .rx_rssi_and_proc_compens_5 = {
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x00 },
280 .tx_ref_pd_voltage = 0x24e,
281 .tx_ref_power = 0x78,
282 .tx_offset_db = 0x0,
283 .tx_rate_limits_normal = {
284 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
285 .tx_rate_limits_degraded = {
286 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
287 .tx_channel_limits_11b = {
288 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
289 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
290 0x22, 0x50 },
291 .tx_channel_limits_ofdm = {
292 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
293 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
294 0x20, 0x50 },
295 .tx_pdv_rate_offsets = {
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
297 .tx_ibias = {
298 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
299 .rx_fem_insertion_loss = 0x14,
300 .tx_ref_pd_voltage_5 = { 0, 0, 0, 0, 0, 0, 0 },
301 .tx_ref_power_5 = { 0, 0, 0, 0, 0, 0, 0 },
302 .tx_offset_db_5 = {0, 0, 0, 0, 0, 0, 0 },
303 .tx_rate_limits_normal_5 = {
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
305 .tx_rate_limits_degraded_5 = {
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
307 .tx_channel_limits_ofdm_5 = {
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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},
314 .tx_pdv_rate_offsets_5 = {
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
316 .tx_ibias_5 = {
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
318 .rx_fem_insertion_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }
319 }
320 }
321};
322
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300323static void wl1271_conf_init(struct wl1271 *wl)
324{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300325
326 /*
327 * This function applies the default configuration to the driver. This
328 * function is invoked upon driver load (spi probe.)
329 *
330 * The configuration is stored in a run-time structure in order to
331 * facilitate for run-time adjustment of any of the parameters. Making
332 * changes to the configuration structure will apply the new values on
333 * the next interface up (wl1271_op_start.)
334 */
335
336 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300337 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300338}
339
340
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300341static int wl1271_plt_init(struct wl1271 *wl)
342{
343 int ret;
344
345 ret = wl1271_acx_init_mem_config(wl);
346 if (ret < 0)
347 return ret;
348
349 ret = wl1271_cmd_data_path(wl, wl->channel, 1);
350 if (ret < 0)
351 return ret;
352
353 return 0;
354}
355
356static void wl1271_disable_interrupts(struct wl1271 *wl)
357{
358 disable_irq(wl->irq);
359}
360
361static void wl1271_power_off(struct wl1271 *wl)
362{
363 wl->set_power(false);
364}
365
366static void wl1271_power_on(struct wl1271 *wl)
367{
368 wl->set_power(true);
369}
370
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300371static void wl1271_fw_status(struct wl1271 *wl,
372 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300373{
374 u32 total = 0;
375 int i;
376
Juuso Oikarinen74621412009-10-12 15:08:54 +0300377 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
378 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300379
380 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
381 "drv_rx_counter = %d, tx_results_counter = %d)",
382 status->intr,
383 status->fw_rx_counter,
384 status->drv_rx_counter,
385 status->tx_results_counter);
386
387 /* update number of available TX blocks */
388 for (i = 0; i < NUM_TX_QUEUES; i++) {
389 u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
390 wl->tx_blocks_freed[i] = status->tx_released_blks[i];
391 wl->tx_blocks_available += cnt;
392 total += cnt;
393 }
394
395 /* if more blocks are available now, schedule some tx work */
396 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300397 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300398
399 /* update the host-chipset time offset */
400 wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
401}
402
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300403static void wl1271_irq_work(struct work_struct *work)
404{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300406 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300407 struct wl1271 *wl =
408 container_of(work, struct wl1271, irq_work);
409
410 mutex_lock(&wl->mutex);
411
412 wl1271_debug(DEBUG_IRQ, "IRQ work");
413
414 if (wl->state == WL1271_STATE_OFF)
415 goto out;
416
417 ret = wl1271_ps_elp_wakeup(wl, true);
418 if (ret < 0)
419 goto out;
420
Juuso Oikarinen74621412009-10-12 15:08:54 +0300421 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300422
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300423 wl1271_fw_status(wl, wl->fw_status);
424 intr = wl->fw_status->intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425 if (!intr) {
426 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
427 goto out_sleep;
428 }
429
430 intr &= WL1271_INTR_MASK;
431
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300432 if (intr & (WL1271_ACX_INTR_EVENT_A |
433 WL1271_ACX_INTR_EVENT_B)) {
434 wl1271_debug(DEBUG_IRQ,
435 "WL1271_ACX_INTR_EVENT (0x%x)", intr);
436 if (intr & WL1271_ACX_INTR_EVENT_A)
437 wl1271_event_handle(wl, 0);
438 else
439 wl1271_event_handle(wl, 1);
440 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300442 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
443 wl1271_debug(DEBUG_IRQ,
444 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300446 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
447 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300448
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300449 if (intr & WL1271_ACX_INTR_DATA) {
450 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
451 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300452
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300453 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300455 /* check for tx results */
456 if (tx_res_cnt)
457 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300458
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300459 wl1271_rx(wl, wl->fw_status);
460 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461
462out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300463 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300464 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465 wl1271_ps_elp_sleep(wl);
466
467out:
468 mutex_unlock(&wl->mutex);
469}
470
471static irqreturn_t wl1271_irq(int irq, void *cookie)
472{
473 struct wl1271 *wl;
474 unsigned long flags;
475
476 wl1271_debug(DEBUG_IRQ, "IRQ");
477
478 wl = cookie;
479
480 /* complete the ELP completion */
481 spin_lock_irqsave(&wl->wl_lock, flags);
482 if (wl->elp_compl) {
483 complete(wl->elp_compl);
484 wl->elp_compl = NULL;
485 }
486
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300487 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300488 spin_unlock_irqrestore(&wl->wl_lock, flags);
489
490 return IRQ_HANDLED;
491}
492
493static int wl1271_fetch_firmware(struct wl1271 *wl)
494{
495 const struct firmware *fw;
496 int ret;
497
498 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
499
500 if (ret < 0) {
501 wl1271_error("could not get firmware: %d", ret);
502 return ret;
503 }
504
505 if (fw->size % 4) {
506 wl1271_error("firmware size is not multiple of 32 bits: %zu",
507 fw->size);
508 ret = -EILSEQ;
509 goto out;
510 }
511
512 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300513 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514
515 if (!wl->fw) {
516 wl1271_error("could not allocate memory for the firmware");
517 ret = -ENOMEM;
518 goto out;
519 }
520
521 memcpy(wl->fw, fw->data, wl->fw_len);
522
523 ret = 0;
524
525out:
526 release_firmware(fw);
527
528 return ret;
529}
530
531static int wl1271_fetch_nvs(struct wl1271 *wl)
532{
533 const struct firmware *fw;
534 int ret;
535
536 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
537
538 if (ret < 0) {
539 wl1271_error("could not get nvs file: %d", ret);
540 return ret;
541 }
542
543 if (fw->size % 4) {
544 wl1271_error("nvs size is not multiple of 32 bits: %zu",
545 fw->size);
546 ret = -EILSEQ;
547 goto out;
548 }
549
550 wl->nvs_len = fw->size;
551 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
552
553 if (!wl->nvs) {
554 wl1271_error("could not allocate memory for the nvs file");
555 ret = -ENOMEM;
556 goto out;
557 }
558
559 memcpy(wl->nvs, fw->data, wl->nvs_len);
560
561 ret = 0;
562
563out:
564 release_firmware(fw);
565
566 return ret;
567}
568
569static void wl1271_fw_wakeup(struct wl1271 *wl)
570{
571 u32 elp_reg;
572
573 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300574 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575}
576
577static int wl1271_setup(struct wl1271 *wl)
578{
579 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
580 if (!wl->fw_status)
581 return -ENOMEM;
582
583 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
584 if (!wl->tx_res_if) {
585 kfree(wl->fw_status);
586 return -ENOMEM;
587 }
588
589 INIT_WORK(&wl->irq_work, wl1271_irq_work);
590 INIT_WORK(&wl->tx_work, wl1271_tx_work);
591 return 0;
592}
593
594static int wl1271_chip_wakeup(struct wl1271 *wl)
595{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300596 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597 int ret = 0;
598
599 wl1271_power_on(wl);
600 msleep(WL1271_POWER_ON_SLEEP);
601 wl1271_spi_reset(wl);
602 wl1271_spi_init(wl);
603
604 /* We don't need a real memory partition here, because we only want
605 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300606 memset(&partition, 0, sizeof(partition));
607 partition.reg.start = REGISTERS_BASE;
608 partition.reg.size = REGISTERS_DOWN_SIZE;
609 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300610
611 /* ELP module wake up */
612 wl1271_fw_wakeup(wl);
613
614 /* whal_FwCtrl_BootSm() */
615
616 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300617 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300618
619 /* 1. check if chip id is valid */
620
621 switch (wl->chip.id) {
622 case CHIP_ID_1271_PG10:
623 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
624 wl->chip.id);
625
626 ret = wl1271_setup(wl);
627 if (ret < 0)
628 goto out;
629 break;
630 case CHIP_ID_1271_PG20:
631 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
632 wl->chip.id);
633
634 ret = wl1271_setup(wl);
635 if (ret < 0)
636 goto out;
637 break;
638 default:
639 wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
640 ret = -ENODEV;
641 goto out;
642 }
643
644 if (wl->fw == NULL) {
645 ret = wl1271_fetch_firmware(wl);
646 if (ret < 0)
647 goto out;
648 }
649
650 /* No NVS from netlink, try to get it from the filesystem */
651 if (wl->nvs == NULL) {
652 ret = wl1271_fetch_nvs(wl);
653 if (ret < 0)
654 goto out;
655 }
656
657out:
658 return ret;
659}
660
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300661struct wl1271_filter_params {
662 unsigned int filters;
663 unsigned int changed;
664 int mc_list_length;
665 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
666};
667
668#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
669 FIF_ALLMULTI | \
670 FIF_FCSFAIL | \
671 FIF_BCN_PRBRESP_PROMISC | \
672 FIF_CONTROL | \
673 FIF_OTHER_BSS)
674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675static void wl1271_filter_work(struct work_struct *work)
676{
677 struct wl1271 *wl =
678 container_of(work, struct wl1271, filter_work);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300679 struct wl1271_filter_params *fp;
680 unsigned long flags;
681 bool enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 int ret;
683
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300684 /* first, get the filter parameters */
685 spin_lock_irqsave(&wl->wl_lock, flags);
686 fp = wl->filter_params;
687 wl->filter_params = NULL;
688 spin_unlock_irqrestore(&wl->wl_lock, flags);
689
690 if (!fp)
691 return;
692
693 /* then, lock the mutex without risk of lock-up */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 mutex_lock(&wl->mutex);
695
696 if (wl->state == WL1271_STATE_OFF)
697 goto out;
698
699 ret = wl1271_ps_elp_wakeup(wl, false);
700 if (ret < 0)
701 goto out;
702
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300703 /* configure the mc filter regardless of the changed flags */
704 if (fp->filters & FIF_ALLMULTI)
705 enabled = false;
706
707 ret = wl1271_acx_group_address_tbl(wl, enabled,
708 fp->mc_list, fp->mc_list_length);
709 if (ret < 0)
710 goto out_sleep;
711
712 /* determine, whether supported filter values have changed */
713 if (fp->changed == 0)
714 goto out;
715
716 /* apply configured filters */
Luciano Coelho0535d9f2009-10-12 15:08:56 +0300717 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718 if (ret < 0)
719 goto out_sleep;
720
721out_sleep:
722 wl1271_ps_elp_sleep(wl);
723
724out:
725 mutex_unlock(&wl->mutex);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300726 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727}
728
729int wl1271_plt_start(struct wl1271 *wl)
730{
731 int ret;
732
733 mutex_lock(&wl->mutex);
734
735 wl1271_notice("power up");
736
737 if (wl->state != WL1271_STATE_OFF) {
738 wl1271_error("cannot go into PLT state because not "
739 "in off state: %d", wl->state);
740 ret = -EBUSY;
741 goto out;
742 }
743
744 wl->state = WL1271_STATE_PLT;
745
746 ret = wl1271_chip_wakeup(wl);
747 if (ret < 0)
748 goto out;
749
750 ret = wl1271_boot(wl);
751 if (ret < 0)
752 goto out;
753
754 wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
755
756 ret = wl1271_plt_init(wl);
757 if (ret < 0)
758 goto out;
759
760out:
761 mutex_unlock(&wl->mutex);
762
763 return ret;
764}
765
766int wl1271_plt_stop(struct wl1271 *wl)
767{
768 int ret = 0;
769
770 mutex_lock(&wl->mutex);
771
772 wl1271_notice("power down");
773
774 if (wl->state != WL1271_STATE_PLT) {
775 wl1271_error("cannot power down because not in PLT "
776 "state: %d", wl->state);
777 ret = -EBUSY;
778 goto out;
779 }
780
781 wl1271_disable_interrupts(wl);
782 wl1271_power_off(wl);
783
784 wl->state = WL1271_STATE_OFF;
785
786out:
787 mutex_unlock(&wl->mutex);
788
789 return ret;
790}
791
792
793static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
794{
795 struct wl1271 *wl = hw->priv;
796
797 skb_queue_tail(&wl->tx_queue, skb);
798
799 /*
800 * The chip specific setup must run before the first TX packet -
801 * before that, the tx_work will not be initialized!
802 */
803
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300804 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805
806 /*
807 * The workqueue is slow to process the tx_queue and we need stop
808 * the queue here, otherwise the queue will get too long.
809 */
810 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
811 ieee80211_stop_queues(wl->hw);
812
813 /*
814 * FIXME: this is racy, the variable is not properly
815 * protected. Maybe fix this by removing the stupid
816 * variable altogether and checking the real queue state?
817 */
818 wl->tx_queue_stopped = true;
819 }
820
821 return NETDEV_TX_OK;
822}
823
824static int wl1271_op_start(struct ieee80211_hw *hw)
825{
826 struct wl1271 *wl = hw->priv;
827 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
840 ret = wl1271_chip_wakeup(wl);
841 if (ret < 0)
842 goto out;
843
844 ret = wl1271_boot(wl);
845 if (ret < 0)
846 goto out;
847
848 ret = wl1271_hw_init(wl);
849 if (ret < 0)
850 goto out;
851
852 wl->state = WL1271_STATE_ON;
853
854 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
855
856out:
857 if (ret < 0)
858 wl1271_power_off(wl);
859
860 mutex_unlock(&wl->mutex);
861
862 return ret;
863}
864
865static void wl1271_op_stop(struct ieee80211_hw *hw)
866{
867 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300868 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869 int i;
870
871 wl1271_info("down");
872
873 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
874
Juuso Oikarinenc87dec92009-10-08 21:56:31 +0300875 /* complete/cancel ongoing work */
876 cancel_work_sync(&wl->filter_work);
877 spin_lock_irqsave(&wl->wl_lock, flags);
878 kfree(wl->filter_params);
879 wl->filter_params = NULL;
880 spin_unlock_irqrestore(&wl->wl_lock, flags);
881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882 mutex_lock(&wl->mutex);
883
884 WARN_ON(wl->state != WL1271_STATE_ON);
885
886 if (wl->scanning) {
887 mutex_unlock(&wl->mutex);
888 ieee80211_scan_completed(wl->hw, true);
889 mutex_lock(&wl->mutex);
890 wl->scanning = false;
891 }
892
893 wl->state = WL1271_STATE_OFF;
894
895 wl1271_disable_interrupts(wl);
896
897 mutex_unlock(&wl->mutex);
898
899 cancel_work_sync(&wl->irq_work);
900 cancel_work_sync(&wl->tx_work);
901 cancel_work_sync(&wl->filter_work);
902
903 mutex_lock(&wl->mutex);
904
905 /* let's notify MAC80211 about the remaining pending TX frames */
906 wl1271_tx_flush(wl);
907 wl1271_power_off(wl);
908
909 memset(wl->bssid, 0, ETH_ALEN);
910 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
911 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300913 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914
915 wl->rx_counter = 0;
916 wl->elp = false;
917 wl->psm = 0;
918 wl->tx_queue_stopped = false;
919 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
920 wl->tx_blocks_available = 0;
921 wl->tx_results_count = 0;
922 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300923 wl->tx_security_last_seq = 0;
924 wl->tx_security_seq_16 = 0;
925 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 wl->time_offset = 0;
927 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300928 wl->joined = false;
929
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930 for (i = 0; i < NUM_TX_QUEUES; i++)
931 wl->tx_blocks_freed[i] = 0;
932
933 wl1271_debugfs_reset(wl);
934 mutex_unlock(&wl->mutex);
935}
936
937static int wl1271_op_add_interface(struct ieee80211_hw *hw,
938 struct ieee80211_if_init_conf *conf)
939{
940 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 int ret = 0;
942
John W. Linvillee5539bc2009-08-18 10:50:34 -0400943 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
944 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945
946 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300947 if (wl->vif) {
948 ret = -EBUSY;
949 goto out;
950 }
951
952 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953
954 switch (conf->type) {
955 case NL80211_IFTYPE_STATION:
956 wl->bss_type = BSS_TYPE_STA_BSS;
957 break;
958 case NL80211_IFTYPE_ADHOC:
959 wl->bss_type = BSS_TYPE_IBSS;
960 break;
961 default:
962 ret = -EOPNOTSUPP;
963 goto out;
964 }
965
966 /* FIXME: what if conf->mac_addr changes? */
967
968out:
969 mutex_unlock(&wl->mutex);
970 return ret;
971}
972
973static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
974 struct ieee80211_if_init_conf *conf)
975{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300976 struct wl1271 *wl = hw->priv;
977
978 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300980 wl->vif = NULL;
981 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982}
983
984#if 0
985static int wl1271_op_config_interface(struct ieee80211_hw *hw,
986 struct ieee80211_vif *vif,
987 struct ieee80211_if_conf *conf)
988{
989 struct wl1271 *wl = hw->priv;
990 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 int ret;
992
David S. Miller32646902009-09-17 10:18:30 -0700993 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
994 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
996 conf->ssid_len);
997
998 mutex_lock(&wl->mutex);
999
1000 ret = wl1271_ps_elp_wakeup(wl, false);
1001 if (ret < 0)
1002 goto out;
1003
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001004 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1005 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1006
1007 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1008
1009 ret = wl1271_cmd_join(wl);
1010 if (ret < 0)
1011 goto out_sleep;
1012 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013
1014 ret = wl1271_cmd_build_null_data(wl);
1015 if (ret < 0)
1016 goto out_sleep;
1017
1018 wl->ssid_len = conf->ssid_len;
1019 if (wl->ssid_len)
1020 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022 if (conf->changed & IEEE80211_IFCC_BEACON) {
1023 beacon = ieee80211_beacon_get(hw, vif);
1024 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1025 beacon->data, beacon->len);
1026
1027 if (ret < 0) {
1028 dev_kfree_skb(beacon);
1029 goto out_sleep;
1030 }
1031
1032 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1033 beacon->data, beacon->len);
1034
1035 dev_kfree_skb(beacon);
1036
1037 if (ret < 0)
1038 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 }
1040
1041out_sleep:
1042 wl1271_ps_elp_sleep(wl);
1043
1044out:
1045 mutex_unlock(&wl->mutex);
1046
1047 return ret;
1048}
1049#endif
1050
1051static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1052{
1053 struct wl1271 *wl = hw->priv;
1054 struct ieee80211_conf *conf = &hw->conf;
1055 int channel, ret = 0;
1056
1057 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1058
1059 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
1060 channel,
1061 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
1062 conf->power_level);
1063
1064 mutex_lock(&wl->mutex);
1065
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001066 wl->band = conf->channel->band;
1067
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 ret = wl1271_ps_elp_wakeup(wl, false);
1069 if (ret < 0)
1070 goto out;
1071
1072 if (channel != wl->channel) {
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001073 /*
1074 * We assume that the stack will configure the right channel
1075 * before associating, so we don't need to send a join
1076 * command here. We will join the right channel when the
1077 * BSSID changes
1078 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 wl->channel = channel;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 }
1081
1082 ret = wl1271_cmd_build_null_data(wl);
1083 if (ret < 0)
1084 goto out_sleep;
1085
1086 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
1087 wl1271_info("psm enabled");
1088
1089 wl->psm_requested = true;
1090
1091 /*
1092 * We enter PSM only if we're already associated.
1093 * If we're not, we'll enter it when joining an SSID,
1094 * through the bss_info_changed() hook.
1095 */
1096 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1097 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1098 wl->psm_requested) {
1099 wl1271_info("psm disabled");
1100
1101 wl->psm_requested = false;
1102
1103 if (wl->psm)
1104 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1105 }
1106
1107 if (conf->power_level != wl->power_level) {
1108 ret = wl1271_acx_tx_power(wl, conf->power_level);
1109 if (ret < 0)
1110 goto out;
1111
1112 wl->power_level = conf->power_level;
1113 }
1114
1115out_sleep:
1116 wl1271_ps_elp_sleep(wl);
1117
1118out:
1119 mutex_unlock(&wl->mutex);
1120
1121 return ret;
1122}
1123
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001124static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1125 struct dev_addr_list *mc_list)
1126{
1127 struct wl1271 *wl = hw->priv;
1128 struct wl1271_filter_params *fp;
1129 unsigned long flags;
1130 int i;
1131
1132 /*
1133 * FIXME: we should return a hash that will be passed to
1134 * configure_filter() instead of saving everything in the context.
1135 */
1136
1137 fp = kzalloc(sizeof(*fp), GFP_KERNEL);
1138 if (!fp) {
1139 wl1271_error("Out of memory setting filters.");
1140 return 0;
1141 }
1142
1143 /* update multicast filtering parameters */
1144 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1145 mc_count = 0;
1146 fp->filters |= FIF_ALLMULTI;
1147 }
1148
1149 fp->mc_list_length = 0;
1150 for (i = 0; i < mc_count; i++) {
1151 if (mc_list->da_addrlen == ETH_ALEN) {
1152 memcpy(fp->mc_list[fp->mc_list_length],
1153 mc_list->da_addr, ETH_ALEN);
1154 fp->mc_list_length++;
1155 } else
1156 wl1271_warning("Unknown mc address length.");
1157 }
1158
Luciano Coelho0535d9f2009-10-12 15:08:56 +03001159 /* FIXME: We still need to set our filters properly */
1160
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001161 spin_lock_irqsave(&wl->wl_lock, flags);
1162 kfree(wl->filter_params);
1163 wl->filter_params = fp;
1164 spin_unlock_irqrestore(&wl->wl_lock, flags);
1165
1166 return 1;
1167}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168
1169static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1170 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001171 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001172{
1173 struct wl1271 *wl = hw->priv;
1174
1175 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1176
1177 *total &= WL1271_SUPPORTED_FILTERS;
1178 changed &= WL1271_SUPPORTED_FILTERS;
1179
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001180 if (!multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181 return;
1182
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183 /*
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001184 * FIXME: for now we are still using a workqueue for filter
1185 * configuration, but with the new mac80211, this is not needed,
1186 * since configure_filter can now sleep. We now have
1187 * prepare_multicast, which needs to be atomic instead.
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001188 */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001189
1190 /* store current filter config */
1191 wl->filter_params->filters = *total;
1192 wl->filter_params->changed = changed;
1193
1194 ieee80211_queue_work(wl->hw, &wl->filter_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195}
1196
1197static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1198 struct ieee80211_vif *vif,
1199 struct ieee80211_sta *sta,
1200 struct ieee80211_key_conf *key_conf)
1201{
1202 struct wl1271 *wl = hw->priv;
1203 const u8 *addr;
1204 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001205 u32 tx_seq_32 = 0;
1206 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207 u8 key_type;
1208
1209 static const u8 bcast_addr[ETH_ALEN] =
1210 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1211
1212 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1213
1214 addr = sta ? sta->addr : bcast_addr;
1215
1216 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1217 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1218 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1219 key_conf->alg, key_conf->keyidx,
1220 key_conf->keylen, key_conf->flags);
1221 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1222
1223 if (is_zero_ether_addr(addr)) {
1224 /* We dont support TX only encryption */
1225 ret = -EOPNOTSUPP;
1226 goto out;
1227 }
1228
1229 mutex_lock(&wl->mutex);
1230
1231 ret = wl1271_ps_elp_wakeup(wl, false);
1232 if (ret < 0)
1233 goto out_unlock;
1234
1235 switch (key_conf->alg) {
1236 case ALG_WEP:
1237 key_type = KEY_WEP;
1238
1239 key_conf->hw_key_idx = key_conf->keyidx;
1240 break;
1241 case ALG_TKIP:
1242 key_type = KEY_TKIP;
1243
1244 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001245 tx_seq_32 = wl->tx_security_seq_32;
1246 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247 break;
1248 case ALG_CCMP:
1249 key_type = KEY_AES;
1250
1251 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001252 tx_seq_32 = wl->tx_security_seq_32;
1253 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254 break;
1255 default:
1256 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1257
1258 ret = -EOPNOTSUPP;
1259 goto out_sleep;
1260 }
1261
1262 switch (cmd) {
1263 case SET_KEY:
1264 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1265 key_conf->keyidx, key_type,
1266 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001267 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268 if (ret < 0) {
1269 wl1271_error("Could not add or replace key");
1270 goto out_sleep;
1271 }
1272 break;
1273
1274 case DISABLE_KEY:
1275 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1276 key_conf->keyidx, key_type,
1277 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001278 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 if (ret < 0) {
1280 wl1271_error("Could not remove key");
1281 goto out_sleep;
1282 }
1283 break;
1284
1285 default:
1286 wl1271_error("Unsupported key cmd 0x%x", cmd);
1287 ret = -EOPNOTSUPP;
1288 goto out_sleep;
1289
1290 break;
1291 }
1292
1293out_sleep:
1294 wl1271_ps_elp_sleep(wl);
1295
1296out_unlock:
1297 mutex_unlock(&wl->mutex);
1298
1299out:
1300 return ret;
1301}
1302
1303static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1304 struct cfg80211_scan_request *req)
1305{
1306 struct wl1271 *wl = hw->priv;
1307 int ret;
1308 u8 *ssid = NULL;
1309 size_t ssid_len = 0;
1310
1311 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1312
1313 if (req->n_ssids) {
1314 ssid = req->ssids[0].ssid;
1315 ssid_len = req->ssids[0].ssid_len;
1316 }
1317
1318 mutex_lock(&wl->mutex);
1319
1320 ret = wl1271_ps_elp_wakeup(wl, false);
1321 if (ret < 0)
1322 goto out;
1323
1324 ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
1325
1326 wl1271_ps_elp_sleep(wl);
1327
1328out:
1329 mutex_unlock(&wl->mutex);
1330
1331 return ret;
1332}
1333
1334static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1335{
1336 struct wl1271 *wl = hw->priv;
1337 int ret;
1338
1339 mutex_lock(&wl->mutex);
1340
1341 ret = wl1271_ps_elp_wakeup(wl, false);
1342 if (ret < 0)
1343 goto out;
1344
1345 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1346 if (ret < 0)
1347 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1348
1349 wl1271_ps_elp_sleep(wl);
1350
1351out:
1352 mutex_unlock(&wl->mutex);
1353
1354 return ret;
1355}
1356
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001357static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1358{
1359 struct ieee80211_supported_band *band;
1360 u32 enabled_rates = 0;
1361 int bit;
1362
1363 band = wl->hw->wiphy->bands[wl->band];
1364 for (bit = 0; bit < band->n_bitrates; bit++) {
1365 if (basic_rate_set & 0x1)
1366 enabled_rates |= band->bitrates[bit].hw_value;
1367 basic_rate_set >>= 1;
1368 }
1369
1370 return enabled_rates;
1371}
1372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1374 struct ieee80211_vif *vif,
1375 struct ieee80211_bss_conf *bss_conf,
1376 u32 changed)
1377{
1378 enum wl1271_cmd_ps_mode mode;
1379 struct wl1271 *wl = hw->priv;
1380 int ret;
1381
1382 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1383
1384 mutex_lock(&wl->mutex);
1385
1386 ret = wl1271_ps_elp_wakeup(wl, false);
1387 if (ret < 0)
1388 goto out;
1389
1390 if (changed & BSS_CHANGED_ASSOC) {
1391 if (bss_conf->assoc) {
1392 wl->aid = bss_conf->aid;
1393
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001394 /*
1395 * with wl1271, we don't need to update the
1396 * beacon_int and dtim_period, because the firmware
1397 * updates it by itself when the first beacon is
1398 * received after a join.
1399 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1401 if (ret < 0)
1402 goto out_sleep;
1403
1404 ret = wl1271_acx_aid(wl, wl->aid);
1405 if (ret < 0)
1406 goto out_sleep;
1407
1408 /* If we want to go in PSM but we're not there yet */
1409 if (wl->psm_requested && !wl->psm) {
1410 mode = STATION_POWER_SAVE_MODE;
1411 ret = wl1271_ps_set_mode(wl, mode);
1412 if (ret < 0)
1413 goto out_sleep;
1414 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001415 } else {
1416 /* use defaults when not associated */
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001417 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
1418 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001420
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001421 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001422
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 if (changed & BSS_CHANGED_ERP_SLOT) {
1424 if (bss_conf->use_short_slot)
1425 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1426 else
1427 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1428 if (ret < 0) {
1429 wl1271_warning("Set slot time failed %d", ret);
1430 goto out_sleep;
1431 }
1432 }
1433
1434 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1435 if (bss_conf->use_short_preamble)
1436 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1437 else
1438 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1439 }
1440
1441 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1442 if (bss_conf->use_cts_prot)
1443 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1444 else
1445 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1446 if (ret < 0) {
1447 wl1271_warning("Set ctsprotect failed %d", ret);
1448 goto out_sleep;
1449 }
1450 }
1451
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001452 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001453 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001454 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001455
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001456 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001457 if (ret < 0) {
1458 wl1271_warning("Set rate policies failed %d", ret);
1459 goto out_sleep;
1460 }
1461 }
1462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463out_sleep:
1464 wl1271_ps_elp_sleep(wl);
1465
1466out:
1467 mutex_unlock(&wl->mutex);
1468}
1469
1470
1471/* can't be const, mac80211 writes to this */
1472static struct ieee80211_rate wl1271_rates[] = {
1473 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001474 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1475 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001477 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1478 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1480 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001481 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1482 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1484 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001485 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1486 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1488 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001489 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1490 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001492 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1493 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001495 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1496 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001498 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1499 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001501 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1502 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001504 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1505 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001507 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1508 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001510 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1511 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512};
1513
1514/* can't be const, mac80211 writes to this */
1515static struct ieee80211_channel wl1271_channels[] = {
1516 { .hw_value = 1, .center_freq = 2412},
1517 { .hw_value = 2, .center_freq = 2417},
1518 { .hw_value = 3, .center_freq = 2422},
1519 { .hw_value = 4, .center_freq = 2427},
1520 { .hw_value = 5, .center_freq = 2432},
1521 { .hw_value = 6, .center_freq = 2437},
1522 { .hw_value = 7, .center_freq = 2442},
1523 { .hw_value = 8, .center_freq = 2447},
1524 { .hw_value = 9, .center_freq = 2452},
1525 { .hw_value = 10, .center_freq = 2457},
1526 { .hw_value = 11, .center_freq = 2462},
1527 { .hw_value = 12, .center_freq = 2467},
1528 { .hw_value = 13, .center_freq = 2472},
1529};
1530
1531/* can't be const, mac80211 writes to this */
1532static struct ieee80211_supported_band wl1271_band_2ghz = {
1533 .channels = wl1271_channels,
1534 .n_channels = ARRAY_SIZE(wl1271_channels),
1535 .bitrates = wl1271_rates,
1536 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1537};
1538
1539static const struct ieee80211_ops wl1271_ops = {
1540 .start = wl1271_op_start,
1541 .stop = wl1271_op_stop,
1542 .add_interface = wl1271_op_add_interface,
1543 .remove_interface = wl1271_op_remove_interface,
1544 .config = wl1271_op_config,
1545/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001546 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547 .configure_filter = wl1271_op_configure_filter,
1548 .tx = wl1271_op_tx,
1549 .set_key = wl1271_op_set_key,
1550 .hw_scan = wl1271_op_hw_scan,
1551 .bss_info_changed = wl1271_op_bss_info_changed,
1552 .set_rts_threshold = wl1271_op_set_rts_threshold,
1553};
1554
1555static int wl1271_register_hw(struct wl1271 *wl)
1556{
1557 int ret;
1558
1559 if (wl->mac80211_registered)
1560 return 0;
1561
1562 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1563
1564 ret = ieee80211_register_hw(wl->hw);
1565 if (ret < 0) {
1566 wl1271_error("unable to register mac80211 hw: %d", ret);
1567 return ret;
1568 }
1569
1570 wl->mac80211_registered = true;
1571
1572 wl1271_notice("loaded");
1573
1574 return 0;
1575}
1576
1577static int wl1271_init_ieee80211(struct wl1271 *wl)
1578{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001579 /* The tx descriptor buffer and the TKIP space. */
1580 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1581 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582
1583 /* unit us */
1584 /* FIXME: find a proper value */
1585 wl->hw->channel_change_time = 10000;
1586
1587 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001588 IEEE80211_HW_NOISE_DBM |
1589 IEEE80211_HW_BEACON_FILTER;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001590
1591 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1592 wl->hw->wiphy->max_scan_ssids = 1;
1593 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1594
1595 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1596
1597 return 0;
1598}
1599
1600static void wl1271_device_release(struct device *dev)
1601{
1602
1603}
1604
1605static struct platform_device wl1271_device = {
1606 .name = "wl1271",
1607 .id = -1,
1608
1609 /* device model insists to have a release function */
1610 .dev = {
1611 .release = wl1271_device_release,
1612 },
1613};
1614
1615#define WL1271_DEFAULT_CHANNEL 0
1616static int __devinit wl1271_probe(struct spi_device *spi)
1617{
1618 struct wl12xx_platform_data *pdata;
1619 struct ieee80211_hw *hw;
1620 struct wl1271 *wl;
1621 int ret, i;
1622 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1623
1624 pdata = spi->dev.platform_data;
1625 if (!pdata) {
1626 wl1271_error("no platform data");
1627 return -ENODEV;
1628 }
1629
1630 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1631 if (!hw) {
1632 wl1271_error("could not alloc ieee80211_hw");
1633 return -ENOMEM;
1634 }
1635
1636 wl = hw->priv;
1637 memset(wl, 0, sizeof(*wl));
1638
1639 wl->hw = hw;
1640 dev_set_drvdata(&spi->dev, wl);
1641 wl->spi = spi;
1642
1643 skb_queue_head_init(&wl->tx_queue);
1644
1645 INIT_WORK(&wl->filter_work, wl1271_filter_work);
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001646 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647 wl->channel = WL1271_DEFAULT_CHANNEL;
1648 wl->scanning = false;
1649 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 wl->rx_counter = 0;
1651 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1652 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1653 wl->elp = false;
1654 wl->psm = 0;
1655 wl->psm_requested = false;
1656 wl->tx_queue_stopped = false;
1657 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001658 wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001659 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001660 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001661 wl->joined = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001663 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664 wl->tx_frames[i] = NULL;
1665
1666 spin_lock_init(&wl->wl_lock);
1667
1668 /*
1669 * In case our MAC address is not correctly set,
1670 * we use a random but Nokia MAC.
1671 */
1672 memcpy(wl->mac_addr, nokia_oui, 3);
1673 get_random_bytes(wl->mac_addr + 3, 3);
1674
1675 wl->state = WL1271_STATE_OFF;
1676 mutex_init(&wl->mutex);
1677
1678 wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
1679 if (!wl->rx_descriptor) {
1680 wl1271_error("could not allocate memory for rx descriptor");
1681 ret = -ENOMEM;
1682 goto out_free;
1683 }
1684
1685 /* This is the only SPI value that we need to set here, the rest
1686 * comes from the board-peripherals file */
1687 spi->bits_per_word = 32;
1688
1689 ret = spi_setup(spi);
1690 if (ret < 0) {
1691 wl1271_error("spi_setup failed");
1692 goto out_free;
1693 }
1694
1695 wl->set_power = pdata->set_power;
1696 if (!wl->set_power) {
1697 wl1271_error("set power function missing in platform data");
1698 ret = -ENODEV;
1699 goto out_free;
1700 }
1701
1702 wl->irq = spi->irq;
1703 if (wl->irq < 0) {
1704 wl1271_error("irq missing in platform data");
1705 ret = -ENODEV;
1706 goto out_free;
1707 }
1708
1709 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1710 if (ret < 0) {
1711 wl1271_error("request_irq() failed: %d", ret);
1712 goto out_free;
1713 }
1714
1715 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1716
1717 disable_irq(wl->irq);
1718
1719 ret = platform_device_register(&wl1271_device);
1720 if (ret) {
1721 wl1271_error("couldn't register platform device");
1722 goto out_irq;
1723 }
1724 dev_set_drvdata(&wl1271_device.dev, wl);
1725
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001726 /* Apply default driver configuration. */
1727 wl1271_conf_init(wl);
1728
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729 ret = wl1271_init_ieee80211(wl);
1730 if (ret)
1731 goto out_platform;
1732
1733 ret = wl1271_register_hw(wl);
1734 if (ret)
1735 goto out_platform;
1736
1737 wl1271_debugfs_init(wl);
1738
1739 wl1271_notice("initialized");
1740
1741 return 0;
1742
1743 out_platform:
1744 platform_device_unregister(&wl1271_device);
1745
1746 out_irq:
1747 free_irq(wl->irq, wl);
1748
1749 out_free:
1750 kfree(wl->rx_descriptor);
1751 wl->rx_descriptor = NULL;
1752
1753 ieee80211_free_hw(hw);
1754
1755 return ret;
1756}
1757
1758static int __devexit wl1271_remove(struct spi_device *spi)
1759{
1760 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
1761
1762 ieee80211_unregister_hw(wl->hw);
1763
1764 wl1271_debugfs_exit(wl);
1765 platform_device_unregister(&wl1271_device);
1766 free_irq(wl->irq, wl);
1767 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001768 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769 wl->fw = NULL;
1770 kfree(wl->nvs);
1771 wl->nvs = NULL;
1772
1773 kfree(wl->rx_descriptor);
1774 wl->rx_descriptor = NULL;
1775
1776 kfree(wl->fw_status);
1777 kfree(wl->tx_res_if);
1778
1779 ieee80211_free_hw(wl->hw);
1780
1781 return 0;
1782}
1783
1784
1785static struct spi_driver wl1271_spi_driver = {
1786 .driver = {
1787 .name = "wl1271",
1788 .bus = &spi_bus_type,
1789 .owner = THIS_MODULE,
1790 },
1791
1792 .probe = wl1271_probe,
1793 .remove = __devexit_p(wl1271_remove),
1794};
1795
1796static int __init wl1271_init(void)
1797{
1798 int ret;
1799
1800 ret = spi_register_driver(&wl1271_spi_driver);
1801 if (ret < 0) {
1802 wl1271_error("failed to register spi driver: %d", ret);
1803 goto out;
1804 }
1805
1806out:
1807 return ret;
1808}
1809
1810static void __exit wl1271_exit(void)
1811{
1812 spi_unregister_driver(&wl1271_spi_driver);
1813
1814 wl1271_notice("unloaded");
1815}
1816
1817module_init(wl1271_init);
1818module_exit(wl1271_exit);
1819
1820MODULE_LICENSE("GPL");
1821MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03001822MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");