blob: 0520b38e8e727f3c6d292b741a61e8fe4cbcee39 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
37#include "wl1271.h"
38#include "wl12xx_80211.h"
39#include "wl1271_reg.h"
40#include "wl1271_spi.h"
41#include "wl1271_event.h"
42#include "wl1271_tx.h"
43#include "wl1271_rx.h"
44#include "wl1271_ps.h"
45#include "wl1271_init.h"
46#include "wl1271_debugfs.h"
47#include "wl1271_cmd.h"
48#include "wl1271_boot.h"
49
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
54 .per_threshold = 7500,
55 .max_scan_compensation_time = 120000,
56 .nfs_sample_interval = 400,
57 .load_ratio = 50,
58 .auto_ps_mode = 0,
59 .probe_req_compensation = 170,
60 .scan_window_compensation = 50,
61 .antenna_config = 0,
62 .beacon_miss_threshold = 60,
63 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
64 .rate_adaptation_snr = 0
65 },
66 .rx = {
67 .rx_msdu_life_time = 512000,
68 .packet_detection_threshold = 0,
69 .ps_poll_timeout = 15,
70 .upsd_timeout = 15,
71 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020072 .rx_cca_threshold = 0,
73 .irq_blk_threshold = 0xFFFF,
74 .irq_pkt_threshold = 0,
75 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030076 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
77 },
78 .tx = {
79 .tx_energy_detection = 0,
80 .rc_conf = {
81 .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
82 .short_retry_limit = 10,
83 .long_retry_limit = 10,
84 .aflags = 0
85 },
86 .ac_conf_count = 4,
87 .ac_conf = {
88 [0] = {
89 .ac = CONF_TX_AC_BE,
90 .cw_min = 15,
91 .cw_max = 63,
92 .aifsn = 3,
93 .tx_op_limit = 0,
94 },
95 [1] = {
96 .ac = CONF_TX_AC_BK,
97 .cw_min = 15,
98 .cw_max = 63,
99 .aifsn = 7,
100 .tx_op_limit = 0,
101 },
102 [2] = {
103 .ac = CONF_TX_AC_VI,
104 .cw_min = 15,
105 .cw_max = 63,
106 .aifsn = CONF_TX_AIFS_PIFS,
107 .tx_op_limit = 3008,
108 },
109 [3] = {
110 .ac = CONF_TX_AC_VO,
111 .cw_min = 15,
112 .cw_max = 63,
113 .aifsn = CONF_TX_AIFS_PIFS,
114 .tx_op_limit = 1504,
115 },
116 },
117 .tid_conf_count = 7,
118 .tid_conf = {
119 [0] = {
120 .queue_id = 0,
121 .channel_type = CONF_CHANNEL_TYPE_DCF,
122 .tsid = CONF_TX_AC_BE,
123 .ps_scheme = CONF_PS_SCHEME_LEGACY,
124 .ack_policy = CONF_ACK_POLICY_LEGACY,
125 .apsd_conf = {0, 0},
126 },
127 [1] = {
128 .queue_id = 1,
129 .channel_type = CONF_CHANNEL_TYPE_DCF,
130 .tsid = CONF_TX_AC_BE,
131 .ps_scheme = CONF_PS_SCHEME_LEGACY,
132 .ack_policy = CONF_ACK_POLICY_LEGACY,
133 .apsd_conf = {0, 0},
134 },
135 [2] = {
136 .queue_id = 2,
137 .channel_type = CONF_CHANNEL_TYPE_DCF,
138 .tsid = CONF_TX_AC_BE,
139 .ps_scheme = CONF_PS_SCHEME_LEGACY,
140 .ack_policy = CONF_ACK_POLICY_LEGACY,
141 .apsd_conf = {0, 0},
142 },
143 [3] = {
144 .queue_id = 3,
145 .channel_type = CONF_CHANNEL_TYPE_DCF,
146 .tsid = CONF_TX_AC_BE,
147 .ps_scheme = CONF_PS_SCHEME_LEGACY,
148 .ack_policy = CONF_ACK_POLICY_LEGACY,
149 .apsd_conf = {0, 0},
150 },
151 [4] = {
152 .queue_id = 4,
153 .channel_type = CONF_CHANNEL_TYPE_DCF,
154 .tsid = CONF_TX_AC_BE,
155 .ps_scheme = CONF_PS_SCHEME_LEGACY,
156 .ack_policy = CONF_ACK_POLICY_LEGACY,
157 .apsd_conf = {0, 0},
158 },
159 [5] = {
160 .queue_id = 5,
161 .channel_type = CONF_CHANNEL_TYPE_DCF,
162 .tsid = CONF_TX_AC_BE,
163 .ps_scheme = CONF_PS_SCHEME_LEGACY,
164 .ack_policy = CONF_ACK_POLICY_LEGACY,
165 .apsd_conf = {0, 0},
166 },
167 [6] = {
168 .queue_id = 6,
169 .channel_type = CONF_CHANNEL_TYPE_DCF,
170 .tsid = CONF_TX_AC_BE,
171 .ps_scheme = CONF_PS_SCHEME_LEGACY,
172 .ack_policy = CONF_ACK_POLICY_LEGACY,
173 .apsd_conf = {0, 0},
174 }
175 },
176 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200177 .tx_compl_timeout = 700,
178 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 },
180 .conn = {
181 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
182 .listen_interval = 0,
183 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
184 .bcn_filt_ie_count = 1,
185 .bcn_filt_ie = {
186 [0] = {
187 .ie = WLAN_EID_CHANNEL_SWITCH,
188 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
189 }
190 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200191 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .bss_lose_timeout = 100,
193 .beacon_rx_timeout = 10000,
194 .broadcast_timeout = 20000,
195 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200196 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300197 .sig_trigger_count = 2,
198 .sig_trigger = {
199 [0] = {
200 .threshold = -75,
201 .pacing = 500,
202 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
203 .type = CONF_TRIG_EVENT_TYPE_EDGE,
204 .direction = CONF_TRIG_EVENT_DIR_LOW,
205 .hysteresis = 2,
206 .index = 0,
207 .enable = 1
208 },
209 [1] = {
210 .threshold = -75,
211 .pacing = 500,
212 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
213 .type = CONF_TRIG_EVENT_TYPE_EDGE,
214 .direction = CONF_TRIG_EVENT_DIR_HIGH,
215 .hysteresis = 2,
216 .index = 1,
217 .enable = 1
218 }
219 },
220 .sig_weights = {
221 .rssi_bcn_avg_weight = 10,
222 .rssi_pkt_avg_weight = 10,
223 .snr_bcn_avg_weight = 10,
224 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300225 },
226 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200227 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200228 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .genparam = {
Luciano Coelhoc7c8adb2009-11-23 23:22:19 +0200232 .ref_clk = CONF_REF_CLK_38_4_E,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .settling_time = 5,
234 .clk_valid_on_wakeup = 0,
235 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300236 .single_dual_band = CONF_SINGLE_BAND,
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200237 .tx_bip_fem_autodetect = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300238 .tx_bip_fem_manufacturer = 1,
239 .settings = 1,
Luciano Coelho76c0f8d2009-12-11 15:40:41 +0200240 .sr_state = 1,
Juuso Oikarinen149e3872009-12-11 15:40:56 +0200241 .srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
242 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
243 .srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
244 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
245 .srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
246 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
Luciano Coelho76c0f8d2009-12-11 15:40:41 +0200247 .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
248 0, 0, 0, 0, 0, 0, 0, 0 },
249 .sr_sen_n_p = 0,
250 .sr_sen_n_p_gain = 0,
251 .sr_sen_nrn = 0,
252 .sr_sen_prn = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300253 },
254 .radioparam = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200255 .rx_trace_loss = 0x24,
256 .tx_trace_loss = 0x0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300257 .rx_rssi_and_proc_compens = {
258 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
Luciano Coelho1b38ea82009-12-11 15:40:51 +0200259 0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 0x00, 0x0a, 0x14 },
261 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
262 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
263 .rx_rssi_and_proc_compens_5 = {
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00 },
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200267 .tx_ref_pd_voltage = 0x1a9,
268 .tx_ref_power = 0x80,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300269 .tx_offset_db = 0x0,
270 .tx_rate_limits_normal = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200271 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .tx_rate_limits_degraded = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200273 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
Luciano Coelhocf18be42009-12-11 15:40:43 +0200274 .tx_rate_limits_extreme = {
275 0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300276 .tx_channel_limits_11b = {
277 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
278 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
279 0x22, 0x50 },
280 .tx_channel_limits_ofdm = {
281 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
282 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
283 0x20, 0x50 },
284 .tx_pdv_rate_offsets = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200285 0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 .tx_ibias = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200287 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
288 .rx_fem_insertion_loss = 0x0e,
Luciano Coelhocf18be42009-12-11 15:40:43 +0200289 .degraded_low_to_normal_threshold = 0x1e,
290 .degraded_normal_to_high_threshold = 0x2d,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300291 .tx_ref_pd_voltage_5 = {
292 0x0190, 0x01a4, 0x01c3, 0x01d8,
293 0x020a, 0x021c },
294 .tx_ref_power_5 = {
295 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
296 .tx_offset_db_5 = {
297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300298 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300299 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300300 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300301 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Luciano Coelhocf18be42009-12-11 15:40:43 +0200302 .tx_rate_limits_extreme_5 = {
303 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300304 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300305 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
306 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
307 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
308 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
309 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300310 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300311 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300312 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300313 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
314 .rx_fem_insertion_loss_5 = {
Luciano Coelhocf18be42009-12-11 15:40:43 +0200315 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
316 .degraded_low_to_normal_threshold_5 = 0x00,
317 .degraded_normal_to_high_threshold_5 = 0x00
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300318 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200319 },
320 .itrim = {
321 .enable = false,
322 .timeout = 50000,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300323 }
324};
325
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300326static LIST_HEAD(wl_list);
327
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300328static void wl1271_conf_init(struct wl1271 *wl)
329{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300330
331 /*
332 * This function applies the default configuration to the driver. This
333 * function is invoked upon driver load (spi probe.)
334 *
335 * The configuration is stored in a run-time structure in order to
336 * facilitate for run-time adjustment of any of the parameters. Making
337 * changes to the configuration structure will apply the new values on
338 * the next interface up (wl1271_op_start.)
339 */
340
341 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300342 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300343
344 if (wl1271_11a_enabled())
345 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300346}
347
348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300349static int wl1271_plt_init(struct wl1271 *wl)
350{
351 int ret;
352
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200353 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200354 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200355 return ret;
356
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200357 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200358 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200359 return ret;
360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300361 ret = wl1271_acx_init_mem_config(wl);
362 if (ret < 0)
363 return ret;
364
Luciano Coelho94210892009-12-11 15:40:55 +0200365 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300366 if (ret < 0)
367 return ret;
368
369 return 0;
370}
371
372static void wl1271_disable_interrupts(struct wl1271 *wl)
373{
374 disable_irq(wl->irq);
375}
376
377static void wl1271_power_off(struct wl1271 *wl)
378{
379 wl->set_power(false);
Luciano Coelho98b2a682009-12-11 15:40:52 +0200380 wl->gpio_power = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300381}
382
383static void wl1271_power_on(struct wl1271 *wl)
384{
385 wl->set_power(true);
Luciano Coelho98b2a682009-12-11 15:40:52 +0200386 wl->gpio_power = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387}
388
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300389static void wl1271_fw_status(struct wl1271 *wl,
390 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300391{
392 u32 total = 0;
393 int i;
394
Juuso Oikarinen74621412009-10-12 15:08:54 +0300395 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
396 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300397
398 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
399 "drv_rx_counter = %d, tx_results_counter = %d)",
400 status->intr,
401 status->fw_rx_counter,
402 status->drv_rx_counter,
403 status->tx_results_counter);
404
405 /* update number of available TX blocks */
406 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300407 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
408 wl->tx_blocks_freed[i];
409
410 wl->tx_blocks_freed[i] =
411 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300412 wl->tx_blocks_available += cnt;
413 total += cnt;
414 }
415
416 /* if more blocks are available now, schedule some tx work */
417 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300418 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300419
420 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300421 wl->time_offset = jiffies_to_usecs(jiffies) -
422 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423}
424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425static void wl1271_irq_work(struct work_struct *work)
426{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300428 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429 struct wl1271 *wl =
430 container_of(work, struct wl1271, irq_work);
431
432 mutex_lock(&wl->mutex);
433
434 wl1271_debug(DEBUG_IRQ, "IRQ work");
435
436 if (wl->state == WL1271_STATE_OFF)
437 goto out;
438
439 ret = wl1271_ps_elp_wakeup(wl, true);
440 if (ret < 0)
441 goto out;
442
Juuso Oikarinen74621412009-10-12 15:08:54 +0300443 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300444
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300445 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300446 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447 if (!intr) {
448 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
449 goto out_sleep;
450 }
451
452 intr &= WL1271_INTR_MASK;
453
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300454 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300455 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200456 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300457 }
458
459 if (intr & WL1271_ACX_INTR_EVENT_B) {
460 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200461 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300462 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300464 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
465 wl1271_debug(DEBUG_IRQ,
466 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300467
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300468 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
469 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300470
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300471 if (intr & WL1271_ACX_INTR_DATA) {
472 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
473 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300474
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300475 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300476
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300477 /* check for tx results */
478 if (tx_res_cnt)
479 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300481 wl1271_rx(wl, wl->fw_status);
482 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300483
484out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300485 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300486 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487 wl1271_ps_elp_sleep(wl);
488
489out:
490 mutex_unlock(&wl->mutex);
491}
492
493static irqreturn_t wl1271_irq(int irq, void *cookie)
494{
495 struct wl1271 *wl;
496 unsigned long flags;
497
498 wl1271_debug(DEBUG_IRQ, "IRQ");
499
500 wl = cookie;
501
502 /* complete the ELP completion */
503 spin_lock_irqsave(&wl->wl_lock, flags);
504 if (wl->elp_compl) {
505 complete(wl->elp_compl);
506 wl->elp_compl = NULL;
507 }
508
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300509 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 spin_unlock_irqrestore(&wl->wl_lock, flags);
511
512 return IRQ_HANDLED;
513}
514
515static int wl1271_fetch_firmware(struct wl1271 *wl)
516{
517 const struct firmware *fw;
518 int ret;
519
520 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
521
522 if (ret < 0) {
523 wl1271_error("could not get firmware: %d", ret);
524 return ret;
525 }
526
527 if (fw->size % 4) {
528 wl1271_error("firmware size is not multiple of 32 bits: %zu",
529 fw->size);
530 ret = -EILSEQ;
531 goto out;
532 }
533
534 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300535 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300536
537 if (!wl->fw) {
538 wl1271_error("could not allocate memory for the firmware");
539 ret = -ENOMEM;
540 goto out;
541 }
542
543 memcpy(wl->fw, fw->data, wl->fw_len);
544
545 ret = 0;
546
547out:
548 release_firmware(fw);
549
550 return ret;
551}
552
553static int wl1271_fetch_nvs(struct wl1271 *wl)
554{
555 const struct firmware *fw;
556 int ret;
557
558 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
559
560 if (ret < 0) {
561 wl1271_error("could not get nvs file: %d", ret);
562 return ret;
563 }
564
565 if (fw->size % 4) {
566 wl1271_error("nvs size is not multiple of 32 bits: %zu",
567 fw->size);
568 ret = -EILSEQ;
569 goto out;
570 }
571
572 wl->nvs_len = fw->size;
573 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
574
575 if (!wl->nvs) {
576 wl1271_error("could not allocate memory for the nvs file");
577 ret = -ENOMEM;
578 goto out;
579 }
580
581 memcpy(wl->nvs, fw->data, wl->nvs_len);
582
583 ret = 0;
584
585out:
586 release_firmware(fw);
587
588 return ret;
589}
590
591static void wl1271_fw_wakeup(struct wl1271 *wl)
592{
593 u32 elp_reg;
594
595 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300596 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597}
598
599static int wl1271_setup(struct wl1271 *wl)
600{
601 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
602 if (!wl->fw_status)
603 return -ENOMEM;
604
605 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
606 if (!wl->tx_res_if) {
607 kfree(wl->fw_status);
608 return -ENOMEM;
609 }
610
611 INIT_WORK(&wl->irq_work, wl1271_irq_work);
612 INIT_WORK(&wl->tx_work, wl1271_tx_work);
613 return 0;
614}
615
616static int wl1271_chip_wakeup(struct wl1271 *wl)
617{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300618 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619 int ret = 0;
620
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200621 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 wl1271_power_on(wl);
623 msleep(WL1271_POWER_ON_SLEEP);
624 wl1271_spi_reset(wl);
625 wl1271_spi_init(wl);
626
627 /* We don't need a real memory partition here, because we only want
628 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300629 memset(&partition, 0, sizeof(partition));
630 partition.reg.start = REGISTERS_BASE;
631 partition.reg.size = REGISTERS_DOWN_SIZE;
632 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633
634 /* ELP module wake up */
635 wl1271_fw_wakeup(wl);
636
637 /* whal_FwCtrl_BootSm() */
638
639 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300640 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641
642 /* 1. check if chip id is valid */
643
644 switch (wl->chip.id) {
645 case CHIP_ID_1271_PG10:
646 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
647 wl->chip.id);
648
649 ret = wl1271_setup(wl);
650 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200651 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652 break;
653 case CHIP_ID_1271_PG20:
654 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
655 wl->chip.id);
656
657 ret = wl1271_setup(wl);
658 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200659 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660 break;
661 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200662 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200664 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 }
666
667 if (wl->fw == NULL) {
668 ret = wl1271_fetch_firmware(wl);
669 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200670 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671 }
672
673 /* No NVS from netlink, try to get it from the filesystem */
674 if (wl->nvs == NULL) {
675 ret = wl1271_fetch_nvs(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 }
679
680out:
681 return ret;
682}
683
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684int wl1271_plt_start(struct wl1271 *wl)
685{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200686 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 int ret;
688
689 mutex_lock(&wl->mutex);
690
691 wl1271_notice("power up");
692
693 if (wl->state != WL1271_STATE_OFF) {
694 wl1271_error("cannot go into PLT state because not "
695 "in off state: %d", wl->state);
696 ret = -EBUSY;
697 goto out;
698 }
699
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200700 while (retries) {
701 retries--;
702 ret = wl1271_chip_wakeup(wl);
703 if (ret < 0)
704 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200706 ret = wl1271_boot(wl);
707 if (ret < 0)
708 goto power_off;
709
710 ret = wl1271_plt_init(wl);
711 if (ret < 0)
712 goto irq_disable;
713
714 /* Make sure power saving is disabled */
715 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
716 if (ret < 0)
717 goto irq_disable;
718
719 wl->state = WL1271_STATE_PLT;
720 wl1271_notice("firmware booted in PLT mode (%s)",
721 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722 goto out;
723
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200724irq_disable:
725 wl1271_disable_interrupts(wl);
726 mutex_unlock(&wl->mutex);
727 /* Unlocking the mutex in the middle of handling is
728 inherently unsafe. In this case we deem it safe to do,
729 because we need to let any possibly pending IRQ out of
730 the system (and while we are WL1271_STATE_OFF the IRQ
731 work function will not do anything.) Also, any other
732 possible concurrent operations will fail due to the
733 current state, hence the wl1271 struct should be safe. */
734 cancel_work_sync(&wl->irq_work);
735 mutex_lock(&wl->mutex);
736power_off:
737 wl1271_power_off(wl);
738 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200740 wl1271_error("firmware boot in PLT mode failed despite %d retries",
741 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300742out:
743 mutex_unlock(&wl->mutex);
744
745 return ret;
746}
747
748int wl1271_plt_stop(struct wl1271 *wl)
749{
750 int ret = 0;
751
752 mutex_lock(&wl->mutex);
753
754 wl1271_notice("power down");
755
756 if (wl->state != WL1271_STATE_PLT) {
757 wl1271_error("cannot power down because not in PLT "
758 "state: %d", wl->state);
759 ret = -EBUSY;
760 goto out;
761 }
762
763 wl1271_disable_interrupts(wl);
764 wl1271_power_off(wl);
765
766 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300767 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300768
769out:
770 mutex_unlock(&wl->mutex);
771
772 return ret;
773}
774
775
776static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
777{
778 struct wl1271 *wl = hw->priv;
779
780 skb_queue_tail(&wl->tx_queue, skb);
781
782 /*
783 * The chip specific setup must run before the first TX packet -
784 * before that, the tx_work will not be initialized!
785 */
786
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300787 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
789 /*
790 * The workqueue is slow to process the tx_queue and we need stop
791 * the queue here, otherwise the queue will get too long.
792 */
793 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
794 ieee80211_stop_queues(wl->hw);
795
796 /*
797 * FIXME: this is racy, the variable is not properly
798 * protected. Maybe fix this by removing the stupid
799 * variable altogether and checking the real queue state?
800 */
801 wl->tx_queue_stopped = true;
802 }
803
804 return NETDEV_TX_OK;
805}
806
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300807static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
808 void *arg)
809{
810 struct net_device *dev;
811 struct wireless_dev *wdev;
812 struct wiphy *wiphy;
813 struct ieee80211_hw *hw;
814 struct wl1271 *wl;
815 struct wl1271 *wl_temp;
816 struct in_device *idev;
817 struct in_ifaddr *ifa = arg;
818 int ret = 0;
819
820 /* FIXME: this ugly function should probably be implemented in the
821 * mac80211, and here should only be a simple callback handling actual
822 * setting of the filters. Now we need to dig up references to
823 * various structures to gain access to what we need.
824 * Also, because of this, there is no "initial" setting of the filter
825 * in "op_start", because we don't want to dig up struct net_device
826 * there - the filter will be set upon first change of the interface
827 * IP address. */
828
829 dev = ifa->ifa_dev->dev;
830
831 wdev = dev->ieee80211_ptr;
832 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200833 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300834
835 wiphy = wdev->wiphy;
836 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200837 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300838
839 hw = wiphy_priv(wiphy);
840 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200841 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300842
843 /* Check that the interface is one supported by this driver. */
844 wl_temp = hw->priv;
845 list_for_each_entry(wl, &wl_list, list) {
846 if (wl == wl_temp)
847 break;
848 }
849 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200850 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300851
852 /* Get the interface IP address for the device. "ifa" will become
853 NULL if:
854 - there is no IPV4 protocol address configured
855 - there are multiple (virtual) IPV4 addresses configured
856 When "ifa" is NULL, filtering will be disabled.
857 */
858 ifa = NULL;
859 idev = dev->ip_ptr;
860 if (idev)
861 ifa = idev->ifa_list;
862
863 if (ifa && ifa->ifa_next)
864 ifa = NULL;
865
866 mutex_lock(&wl->mutex);
867
868 if (wl->state == WL1271_STATE_OFF)
869 goto out;
870
871 ret = wl1271_ps_elp_wakeup(wl, false);
872 if (ret < 0)
873 goto out;
874 if (ifa)
875 ret = wl1271_acx_arp_ip_filter(wl, true,
876 (u8 *)&ifa->ifa_address,
877 ACX_IPV4_VERSION);
878 else
879 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
880 ACX_IPV4_VERSION);
881 wl1271_ps_elp_sleep(wl);
882
883out:
884 mutex_unlock(&wl->mutex);
885
Luciano Coelho17d72652009-11-23 23:22:15 +0200886 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300887}
888
889static struct notifier_block wl1271_dev_notifier = {
890 .notifier_call = wl1271_dev_notify,
891};
892
893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894static int wl1271_op_start(struct ieee80211_hw *hw)
895{
896 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200897 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 int ret = 0;
899
900 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
901
902 mutex_lock(&wl->mutex);
903
904 if (wl->state != WL1271_STATE_OFF) {
905 wl1271_error("cannot start because not in off state: %d",
906 wl->state);
907 ret = -EBUSY;
908 goto out;
909 }
910
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200911 while (retries) {
912 retries--;
913 ret = wl1271_chip_wakeup(wl);
914 if (ret < 0)
915 goto power_off;
916
917 ret = wl1271_boot(wl);
918 if (ret < 0)
919 goto power_off;
920
921 ret = wl1271_hw_init(wl);
922 if (ret < 0)
923 goto irq_disable;
924
925 wl->state = WL1271_STATE_ON;
926 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927 goto out;
928
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200929irq_disable:
930 wl1271_disable_interrupts(wl);
931 mutex_unlock(&wl->mutex);
932 /* Unlocking the mutex in the middle of handling is
933 inherently unsafe. In this case we deem it safe to do,
934 because we need to let any possibly pending IRQ out of
935 the system (and while we are WL1271_STATE_OFF the IRQ
936 work function will not do anything.) Also, any other
937 possible concurrent operations will fail due to the
938 current state, hence the wl1271 struct should be safe. */
939 cancel_work_sync(&wl->irq_work);
940 mutex_lock(&wl->mutex);
941power_off:
942 wl1271_power_off(wl);
943 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200945 wl1271_error("firmware boot failed despite %d retries",
946 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300947out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 mutex_unlock(&wl->mutex);
949
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300950 if (!ret) {
951 list_add(&wl->list, &wl_list);
952 register_inetaddr_notifier(&wl1271_dev_notifier);
953 }
954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955 return ret;
956}
957
958static void wl1271_op_stop(struct ieee80211_hw *hw)
959{
960 struct wl1271 *wl = hw->priv;
961 int i;
962
963 wl1271_info("down");
964
965 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
966
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300967 unregister_inetaddr_notifier(&wl1271_dev_notifier);
968 list_del(&wl->list);
969
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 mutex_lock(&wl->mutex);
971
972 WARN_ON(wl->state != WL1271_STATE_ON);
973
974 if (wl->scanning) {
975 mutex_unlock(&wl->mutex);
976 ieee80211_scan_completed(wl->hw, true);
977 mutex_lock(&wl->mutex);
978 wl->scanning = false;
979 }
980
981 wl->state = WL1271_STATE_OFF;
982
983 wl1271_disable_interrupts(wl);
984
985 mutex_unlock(&wl->mutex);
986
987 cancel_work_sync(&wl->irq_work);
988 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989
990 mutex_lock(&wl->mutex);
991
992 /* let's notify MAC80211 about the remaining pending TX frames */
993 wl1271_tx_flush(wl);
994 wl1271_power_off(wl);
995
996 memset(wl->bssid, 0, ETH_ALEN);
997 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
998 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001000 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001
1002 wl->rx_counter = 0;
1003 wl->elp = false;
1004 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001005 wl->psm_entry_retry = 0;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001006 wl->associated = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 wl->tx_queue_stopped = false;
1008 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1009 wl->tx_blocks_available = 0;
1010 wl->tx_results_count = 0;
1011 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001012 wl->tx_security_last_seq = 0;
1013 wl->tx_security_seq_16 = 0;
1014 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 wl->time_offset = 0;
1016 wl->session_counter = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001017 wl->joined = false;
1018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 for (i = 0; i < NUM_TX_QUEUES; i++)
1020 wl->tx_blocks_freed[i] = 0;
1021
1022 wl1271_debugfs_reset(wl);
1023 mutex_unlock(&wl->mutex);
1024}
1025
1026static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1027 struct ieee80211_if_init_conf *conf)
1028{
1029 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 int ret = 0;
1031
John W. Linvillee5539bc2009-08-18 10:50:34 -04001032 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1033 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
1035 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001036 if (wl->vif) {
1037 ret = -EBUSY;
1038 goto out;
1039 }
1040
1041 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042
1043 switch (conf->type) {
1044 case NL80211_IFTYPE_STATION:
1045 wl->bss_type = BSS_TYPE_STA_BSS;
1046 break;
1047 case NL80211_IFTYPE_ADHOC:
1048 wl->bss_type = BSS_TYPE_IBSS;
1049 break;
1050 default:
1051 ret = -EOPNOTSUPP;
1052 goto out;
1053 }
1054
1055 /* FIXME: what if conf->mac_addr changes? */
1056
1057out:
1058 mutex_unlock(&wl->mutex);
1059 return ret;
1060}
1061
1062static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1063 struct ieee80211_if_init_conf *conf)
1064{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001065 struct wl1271 *wl = hw->priv;
1066
1067 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001069 wl->vif = NULL;
1070 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071}
1072
1073#if 0
1074static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1075 struct ieee80211_vif *vif,
1076 struct ieee80211_if_conf *conf)
1077{
1078 struct wl1271 *wl = hw->priv;
1079 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 int ret;
1081
David S. Miller32646902009-09-17 10:18:30 -07001082 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1083 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1085 conf->ssid_len);
1086
1087 mutex_lock(&wl->mutex);
1088
1089 ret = wl1271_ps_elp_wakeup(wl, false);
1090 if (ret < 0)
1091 goto out;
1092
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001093 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1094 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1095
1096 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1097
1098 ret = wl1271_cmd_join(wl);
1099 if (ret < 0)
1100 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001102 ret = wl1271_cmd_build_null_data(wl);
1103 if (ret < 0)
1104 goto out_sleep;
1105 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106
1107 wl->ssid_len = conf->ssid_len;
1108 if (wl->ssid_len)
1109 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 if (conf->changed & IEEE80211_IFCC_BEACON) {
1112 beacon = ieee80211_beacon_get(hw, vif);
1113 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1114 beacon->data, beacon->len);
1115
1116 if (ret < 0) {
1117 dev_kfree_skb(beacon);
1118 goto out_sleep;
1119 }
1120
1121 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1122 beacon->data, beacon->len);
1123
1124 dev_kfree_skb(beacon);
1125
1126 if (ret < 0)
1127 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128 }
1129
1130out_sleep:
1131 wl1271_ps_elp_sleep(wl);
1132
1133out:
1134 mutex_unlock(&wl->mutex);
1135
1136 return ret;
1137}
1138#endif
1139
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001140static int wl1271_join_channel(struct wl1271 *wl, int channel)
1141{
1142 int ret;
1143 /* we need to use a dummy BSSID for now */
1144 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1145 0xad, 0xbe, 0xef };
1146
1147 /* disable mac filter, so we hear everything */
1148 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1149
1150 wl->channel = channel;
1151 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1152
1153 ret = wl1271_cmd_join(wl);
1154 if (ret < 0)
1155 goto out;
1156
1157 wl->joined = true;
1158
1159out:
1160 return ret;
1161}
1162
1163static int wl1271_unjoin_channel(struct wl1271 *wl)
1164{
1165 int ret;
1166
1167 /* to stop listening to a channel, we disconnect */
1168 ret = wl1271_cmd_disconnect(wl);
1169 if (ret < 0)
1170 goto out;
1171
1172 wl->joined = false;
1173 wl->channel = 0;
1174 memset(wl->bssid, 0, ETH_ALEN);
1175 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1176
1177out:
1178 return ret;
1179}
1180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1182{
1183 struct wl1271 *wl = hw->priv;
1184 struct ieee80211_conf *conf = &hw->conf;
1185 int channel, ret = 0;
1186
1187 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1188
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001189 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001190 channel,
1191 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001192 conf->power_level,
1193 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194
1195 mutex_lock(&wl->mutex);
1196
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001197 wl->band = conf->channel->band;
1198
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001199 ret = wl1271_ps_elp_wakeup(wl, false);
1200 if (ret < 0)
1201 goto out;
1202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1204 if (conf->flags & IEEE80211_CONF_IDLE && wl->joined)
1205 wl1271_unjoin_channel(wl);
1206 else
1207 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001208
1209 if (conf->flags & IEEE80211_CONF_IDLE) {
1210 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
1211 wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC);
1212 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213 }
1214
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001215 /* if the channel changes while joined, join again */
1216 if (channel != wl->channel && wl->joined)
1217 wl1271_join_channel(wl, channel);
1218
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 wl->psm_requested = true;
1221
1222 /*
1223 * We enter PSM only if we're already associated.
1224 * If we're not, we'll enter it when joining an SSID,
1225 * through the bss_info_changed() hook.
1226 */
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001227 if (wl->associated) {
1228 wl1271_info("psm enabled");
1229 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1230 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1232 wl->psm_requested) {
1233 wl1271_info("psm disabled");
1234
1235 wl->psm_requested = false;
1236
1237 if (wl->psm)
1238 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1239 }
1240
1241 if (conf->power_level != wl->power_level) {
1242 ret = wl1271_acx_tx_power(wl, conf->power_level);
1243 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001244 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245
1246 wl->power_level = conf->power_level;
1247 }
1248
1249out_sleep:
1250 wl1271_ps_elp_sleep(wl);
1251
1252out:
1253 mutex_unlock(&wl->mutex);
1254
1255 return ret;
1256}
1257
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001258struct wl1271_filter_params {
1259 bool enabled;
1260 int mc_list_length;
1261 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1262};
1263
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001264static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1265 struct dev_addr_list *mc_list)
1266{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001267 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001268 int i;
1269
Juuso Oikarinen74441132009-10-13 12:47:53 +03001270 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001271 if (!fp) {
1272 wl1271_error("Out of memory setting filters.");
1273 return 0;
1274 }
1275
1276 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001277 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001278 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1279 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001280 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001281 }
1282
1283 fp->mc_list_length = 0;
1284 for (i = 0; i < mc_count; i++) {
1285 if (mc_list->da_addrlen == ETH_ALEN) {
1286 memcpy(fp->mc_list[fp->mc_list_length],
1287 mc_list->da_addr, ETH_ALEN);
1288 fp->mc_list_length++;
1289 } else
1290 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001291 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001292 }
1293
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001294 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001295}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001297#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1298 FIF_ALLMULTI | \
1299 FIF_FCSFAIL | \
1300 FIF_BCN_PRBRESP_PROMISC | \
1301 FIF_CONTROL | \
1302 FIF_OTHER_BSS)
1303
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1305 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001306 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001308 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001310 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311
1312 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1313
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001314 mutex_lock(&wl->mutex);
1315
1316 if (wl->state == WL1271_STATE_OFF)
1317 goto out;
1318
1319 ret = wl1271_ps_elp_wakeup(wl, false);
1320 if (ret < 0)
1321 goto out;
1322
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323 *total &= WL1271_SUPPORTED_FILTERS;
1324 changed &= WL1271_SUPPORTED_FILTERS;
1325
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001326 if (*total & FIF_ALLMULTI)
1327 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1328 else if (fp)
1329 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1330 fp->mc_list,
1331 fp->mc_list_length);
1332 if (ret < 0)
1333 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001335 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001336
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001337 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001338
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001339 /* determine, whether supported filter values have changed */
1340 if (changed == 0)
1341 goto out_sleep;
1342
1343 /* apply configured filters */
1344 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1345 if (ret < 0)
1346 goto out_sleep;
1347
1348out_sleep:
1349 wl1271_ps_elp_sleep(wl);
1350
1351out:
1352 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353}
1354
1355static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1356 struct ieee80211_vif *vif,
1357 struct ieee80211_sta *sta,
1358 struct ieee80211_key_conf *key_conf)
1359{
1360 struct wl1271 *wl = hw->priv;
1361 const u8 *addr;
1362 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001363 u32 tx_seq_32 = 0;
1364 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 u8 key_type;
1366
1367 static const u8 bcast_addr[ETH_ALEN] =
1368 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1369
1370 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1371
1372 addr = sta ? sta->addr : bcast_addr;
1373
1374 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1375 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1376 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1377 key_conf->alg, key_conf->keyidx,
1378 key_conf->keylen, key_conf->flags);
1379 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1380
1381 if (is_zero_ether_addr(addr)) {
1382 /* We dont support TX only encryption */
1383 ret = -EOPNOTSUPP;
1384 goto out;
1385 }
1386
1387 mutex_lock(&wl->mutex);
1388
1389 ret = wl1271_ps_elp_wakeup(wl, false);
1390 if (ret < 0)
1391 goto out_unlock;
1392
1393 switch (key_conf->alg) {
1394 case ALG_WEP:
1395 key_type = KEY_WEP;
1396
1397 key_conf->hw_key_idx = key_conf->keyidx;
1398 break;
1399 case ALG_TKIP:
1400 key_type = KEY_TKIP;
1401
1402 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001403 tx_seq_32 = wl->tx_security_seq_32;
1404 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405 break;
1406 case ALG_CCMP:
1407 key_type = KEY_AES;
1408
1409 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001410 tx_seq_32 = wl->tx_security_seq_32;
1411 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 break;
1413 default:
1414 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1415
1416 ret = -EOPNOTSUPP;
1417 goto out_sleep;
1418 }
1419
1420 switch (cmd) {
1421 case SET_KEY:
1422 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1423 key_conf->keyidx, key_type,
1424 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001425 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426 if (ret < 0) {
1427 wl1271_error("Could not add or replace key");
1428 goto out_sleep;
1429 }
1430 break;
1431
1432 case DISABLE_KEY:
1433 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1434 key_conf->keyidx, key_type,
1435 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001436 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437 if (ret < 0) {
1438 wl1271_error("Could not remove key");
1439 goto out_sleep;
1440 }
1441 break;
1442
1443 default:
1444 wl1271_error("Unsupported key cmd 0x%x", cmd);
1445 ret = -EOPNOTSUPP;
1446 goto out_sleep;
1447
1448 break;
1449 }
1450
1451out_sleep:
1452 wl1271_ps_elp_sleep(wl);
1453
1454out_unlock:
1455 mutex_unlock(&wl->mutex);
1456
1457out:
1458 return ret;
1459}
1460
1461static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1462 struct cfg80211_scan_request *req)
1463{
1464 struct wl1271 *wl = hw->priv;
1465 int ret;
1466 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001467 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468
1469 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1470
1471 if (req->n_ssids) {
1472 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001473 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 }
1475
1476 mutex_lock(&wl->mutex);
1477
1478 ret = wl1271_ps_elp_wakeup(wl, false);
1479 if (ret < 0)
1480 goto out;
1481
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001482 if (wl1271_11a_enabled())
1483 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1484 WL1271_SCAN_BAND_DUAL, 3);
1485 else
1486 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1487 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488
1489 wl1271_ps_elp_sleep(wl);
1490
1491out:
1492 mutex_unlock(&wl->mutex);
1493
1494 return ret;
1495}
1496
1497static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1498{
1499 struct wl1271 *wl = hw->priv;
1500 int ret;
1501
1502 mutex_lock(&wl->mutex);
1503
1504 ret = wl1271_ps_elp_wakeup(wl, false);
1505 if (ret < 0)
1506 goto out;
1507
1508 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1509 if (ret < 0)
1510 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1511
1512 wl1271_ps_elp_sleep(wl);
1513
1514out:
1515 mutex_unlock(&wl->mutex);
1516
1517 return ret;
1518}
1519
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001520static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1521{
1522 struct ieee80211_supported_band *band;
1523 u32 enabled_rates = 0;
1524 int bit;
1525
1526 band = wl->hw->wiphy->bands[wl->band];
1527 for (bit = 0; bit < band->n_bitrates; bit++) {
1528 if (basic_rate_set & 0x1)
1529 enabled_rates |= band->bitrates[bit].hw_value;
1530 basic_rate_set >>= 1;
1531 }
1532
1533 return enabled_rates;
1534}
1535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1537 struct ieee80211_vif *vif,
1538 struct ieee80211_bss_conf *bss_conf,
1539 u32 changed)
1540{
1541 enum wl1271_cmd_ps_mode mode;
1542 struct wl1271 *wl = hw->priv;
1543 int ret;
1544
1545 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1546
1547 mutex_lock(&wl->mutex);
1548
1549 ret = wl1271_ps_elp_wakeup(wl, false);
1550 if (ret < 0)
1551 goto out;
1552
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001553 if ((changed & BSS_CHANGED_BSSID) &&
1554 /*
1555 * Now we know the correct bssid, so we send a new join command
1556 * and enable the BSSID filter
1557 */
1558 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1559 wl->rx_config |= CFG_BSSID_FILTER_EN;
1560 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Luciano Coelhobdcbbb92009-12-11 15:40:48 +02001561 ret = wl1271_cmd_build_null_data(wl);
1562 if (ret < 0) {
1563 wl1271_warning("cmd buld null data failed %d",
1564 ret);
1565 goto out_sleep;
1566 }
Luciano Coelhocd264762009-12-11 15:40:47 +02001567 ret = wl1271_cmd_join(wl);
1568 if (ret < 0) {
1569 wl1271_warning("cmd join failed %d", ret);
1570 goto out_sleep;
1571 }
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001572 wl->joined = true;
1573 }
1574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 if (changed & BSS_CHANGED_ASSOC) {
1576 if (bss_conf->assoc) {
1577 wl->aid = bss_conf->aid;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001578 wl->associated = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001580 /*
1581 * with wl1271, we don't need to update the
1582 * beacon_int and dtim_period, because the firmware
1583 * updates it by itself when the first beacon is
1584 * received after a join.
1585 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001586 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1587 if (ret < 0)
1588 goto out_sleep;
1589
1590 ret = wl1271_acx_aid(wl, wl->aid);
1591 if (ret < 0)
1592 goto out_sleep;
1593
1594 /* If we want to go in PSM but we're not there yet */
1595 if (wl->psm_requested && !wl->psm) {
1596 mode = STATION_POWER_SAVE_MODE;
1597 ret = wl1271_ps_set_mode(wl, mode);
1598 if (ret < 0)
1599 goto out_sleep;
1600 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001601 } else {
1602 /* use defaults when not associated */
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001603 wl->associated = false;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001604 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001606
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001609 if (changed & BSS_CHANGED_ERP_SLOT) {
1610 if (bss_conf->use_short_slot)
1611 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1612 else
1613 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1614 if (ret < 0) {
1615 wl1271_warning("Set slot time failed %d", ret);
1616 goto out_sleep;
1617 }
1618 }
1619
1620 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1621 if (bss_conf->use_short_preamble)
1622 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1623 else
1624 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1625 }
1626
1627 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1628 if (bss_conf->use_cts_prot)
1629 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1630 else
1631 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1632 if (ret < 0) {
1633 wl1271_warning("Set ctsprotect failed %d", ret);
1634 goto out_sleep;
1635 }
1636 }
1637
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001638 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001639 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001640 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001641
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001642 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001643 if (ret < 0) {
1644 wl1271_warning("Set rate policies failed %d", ret);
1645 goto out_sleep;
1646 }
1647 }
1648
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649out_sleep:
1650 wl1271_ps_elp_sleep(wl);
1651
1652out:
1653 mutex_unlock(&wl->mutex);
1654}
1655
1656
1657/* can't be const, mac80211 writes to this */
1658static struct ieee80211_rate wl1271_rates[] = {
1659 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001660 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1661 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001663 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1664 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1666 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001667 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1668 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001669 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1670 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001671 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1672 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001673 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1674 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001675 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1676 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001677 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001678 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1679 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001680 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001681 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1682 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001683 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001684 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1685 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001687 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1688 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001689 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001690 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1691 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001692 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001693 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1694 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001695 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001696 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1697 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698};
1699
1700/* can't be const, mac80211 writes to this */
1701static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001702 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1703 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1704 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1705 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1706 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1707 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1708 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1709 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1710 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1711 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1712 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1713 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1714 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715};
1716
1717/* can't be const, mac80211 writes to this */
1718static struct ieee80211_supported_band wl1271_band_2ghz = {
1719 .channels = wl1271_channels,
1720 .n_channels = ARRAY_SIZE(wl1271_channels),
1721 .bitrates = wl1271_rates,
1722 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1723};
1724
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001725/* 5 GHz data rates for WL1273 */
1726static struct ieee80211_rate wl1271_rates_5ghz[] = {
1727 { .bitrate = 60,
1728 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1729 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1730 { .bitrate = 90,
1731 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1732 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1733 { .bitrate = 120,
1734 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1735 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1736 { .bitrate = 180,
1737 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1738 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1739 { .bitrate = 240,
1740 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1741 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1742 { .bitrate = 360,
1743 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1744 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1745 { .bitrate = 480,
1746 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1747 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1748 { .bitrate = 540,
1749 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1750 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1751};
1752
1753/* 5 GHz band channels for WL1273 */
1754static struct ieee80211_channel wl1271_channels_5ghz[] = {
1755 { .hw_value = 183, .center_freq = 4915},
1756 { .hw_value = 184, .center_freq = 4920},
1757 { .hw_value = 185, .center_freq = 4925},
1758 { .hw_value = 187, .center_freq = 4935},
1759 { .hw_value = 188, .center_freq = 4940},
1760 { .hw_value = 189, .center_freq = 4945},
1761 { .hw_value = 192, .center_freq = 4960},
1762 { .hw_value = 196, .center_freq = 4980},
1763 { .hw_value = 7, .center_freq = 5035},
1764 { .hw_value = 8, .center_freq = 5040},
1765 { .hw_value = 9, .center_freq = 5045},
1766 { .hw_value = 11, .center_freq = 5055},
1767 { .hw_value = 12, .center_freq = 5060},
1768 { .hw_value = 16, .center_freq = 5080},
1769 { .hw_value = 34, .center_freq = 5170},
1770 { .hw_value = 36, .center_freq = 5180},
1771 { .hw_value = 38, .center_freq = 5190},
1772 { .hw_value = 40, .center_freq = 5200},
1773 { .hw_value = 42, .center_freq = 5210},
1774 { .hw_value = 44, .center_freq = 5220},
1775 { .hw_value = 46, .center_freq = 5230},
1776 { .hw_value = 48, .center_freq = 5240},
1777 { .hw_value = 52, .center_freq = 5260},
1778 { .hw_value = 56, .center_freq = 5280},
1779 { .hw_value = 60, .center_freq = 5300},
1780 { .hw_value = 64, .center_freq = 5320},
1781 { .hw_value = 100, .center_freq = 5500},
1782 { .hw_value = 104, .center_freq = 5520},
1783 { .hw_value = 108, .center_freq = 5540},
1784 { .hw_value = 112, .center_freq = 5560},
1785 { .hw_value = 116, .center_freq = 5580},
1786 { .hw_value = 120, .center_freq = 5600},
1787 { .hw_value = 124, .center_freq = 5620},
1788 { .hw_value = 128, .center_freq = 5640},
1789 { .hw_value = 132, .center_freq = 5660},
1790 { .hw_value = 136, .center_freq = 5680},
1791 { .hw_value = 140, .center_freq = 5700},
1792 { .hw_value = 149, .center_freq = 5745},
1793 { .hw_value = 153, .center_freq = 5765},
1794 { .hw_value = 157, .center_freq = 5785},
1795 { .hw_value = 161, .center_freq = 5805},
1796 { .hw_value = 165, .center_freq = 5825},
1797};
1798
1799
1800static struct ieee80211_supported_band wl1271_band_5ghz = {
1801 .channels = wl1271_channels_5ghz,
1802 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1803 .bitrates = wl1271_rates_5ghz,
1804 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1805};
1806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807static const struct ieee80211_ops wl1271_ops = {
1808 .start = wl1271_op_start,
1809 .stop = wl1271_op_stop,
1810 .add_interface = wl1271_op_add_interface,
1811 .remove_interface = wl1271_op_remove_interface,
1812 .config = wl1271_op_config,
1813/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001814 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001815 .configure_filter = wl1271_op_configure_filter,
1816 .tx = wl1271_op_tx,
1817 .set_key = wl1271_op_set_key,
1818 .hw_scan = wl1271_op_hw_scan,
1819 .bss_info_changed = wl1271_op_bss_info_changed,
1820 .set_rts_threshold = wl1271_op_set_rts_threshold,
1821};
1822
1823static int wl1271_register_hw(struct wl1271 *wl)
1824{
1825 int ret;
1826
1827 if (wl->mac80211_registered)
1828 return 0;
1829
1830 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1831
1832 ret = ieee80211_register_hw(wl->hw);
1833 if (ret < 0) {
1834 wl1271_error("unable to register mac80211 hw: %d", ret);
1835 return ret;
1836 }
1837
1838 wl->mac80211_registered = true;
1839
1840 wl1271_notice("loaded");
1841
1842 return 0;
1843}
1844
1845static int wl1271_init_ieee80211(struct wl1271 *wl)
1846{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001847 /* The tx descriptor buffer and the TKIP space. */
1848 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1849 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001850
1851 /* unit us */
1852 /* FIXME: find a proper value */
1853 wl->hw->channel_change_time = 10000;
1854
1855 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001856 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001857 IEEE80211_HW_BEACON_FILTER |
1858 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859
1860 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1861 wl->hw->wiphy->max_scan_ssids = 1;
1862 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1863
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001864 if (wl1271_11a_enabled())
1865 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1866
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001867 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1868
1869 return 0;
1870}
1871
1872static void wl1271_device_release(struct device *dev)
1873{
1874
1875}
1876
1877static struct platform_device wl1271_device = {
1878 .name = "wl1271",
1879 .id = -1,
1880
1881 /* device model insists to have a release function */
1882 .dev = {
1883 .release = wl1271_device_release,
1884 },
1885};
1886
1887#define WL1271_DEFAULT_CHANNEL 0
1888static int __devinit wl1271_probe(struct spi_device *spi)
1889{
1890 struct wl12xx_platform_data *pdata;
1891 struct ieee80211_hw *hw;
1892 struct wl1271 *wl;
1893 int ret, i;
1894 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1895
1896 pdata = spi->dev.platform_data;
1897 if (!pdata) {
1898 wl1271_error("no platform data");
1899 return -ENODEV;
1900 }
1901
1902 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1903 if (!hw) {
1904 wl1271_error("could not alloc ieee80211_hw");
1905 return -ENOMEM;
1906 }
1907
1908 wl = hw->priv;
1909 memset(wl, 0, sizeof(*wl));
1910
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001911 INIT_LIST_HEAD(&wl->list);
1912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913 wl->hw = hw;
1914 dev_set_drvdata(&spi->dev, wl);
1915 wl->spi = spi;
1916
1917 skb_queue_head_init(&wl->tx_queue);
1918
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001919 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920 wl->channel = WL1271_DEFAULT_CHANNEL;
1921 wl->scanning = false;
1922 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 wl->rx_counter = 0;
1924 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1925 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1926 wl->elp = false;
1927 wl->psm = 0;
1928 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001929 wl->psm_entry_retry = 0;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001930 wl->associated = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 wl->tx_queue_stopped = false;
1932 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001933 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001934 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001935 wl->vif = NULL;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001936 wl->joined = false;
Luciano Coelho98b2a682009-12-11 15:40:52 +02001937 wl->gpio_power = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001939 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 wl->tx_frames[i] = NULL;
1941
1942 spin_lock_init(&wl->wl_lock);
1943
1944 /*
1945 * In case our MAC address is not correctly set,
1946 * we use a random but Nokia MAC.
1947 */
1948 memcpy(wl->mac_addr, nokia_oui, 3);
1949 get_random_bytes(wl->mac_addr + 3, 3);
1950
1951 wl->state = WL1271_STATE_OFF;
1952 mutex_init(&wl->mutex);
1953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 /* This is the only SPI value that we need to set here, the rest
1955 * comes from the board-peripherals file */
1956 spi->bits_per_word = 32;
1957
1958 ret = spi_setup(spi);
1959 if (ret < 0) {
1960 wl1271_error("spi_setup failed");
1961 goto out_free;
1962 }
1963
1964 wl->set_power = pdata->set_power;
1965 if (!wl->set_power) {
1966 wl1271_error("set power function missing in platform data");
1967 ret = -ENODEV;
1968 goto out_free;
1969 }
1970
1971 wl->irq = spi->irq;
1972 if (wl->irq < 0) {
1973 wl1271_error("irq missing in platform data");
1974 ret = -ENODEV;
1975 goto out_free;
1976 }
1977
1978 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1979 if (ret < 0) {
1980 wl1271_error("request_irq() failed: %d", ret);
1981 goto out_free;
1982 }
1983
1984 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1985
1986 disable_irq(wl->irq);
1987
1988 ret = platform_device_register(&wl1271_device);
1989 if (ret) {
1990 wl1271_error("couldn't register platform device");
1991 goto out_irq;
1992 }
1993 dev_set_drvdata(&wl1271_device.dev, wl);
1994
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001995 /* Apply default driver configuration. */
1996 wl1271_conf_init(wl);
1997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998 ret = wl1271_init_ieee80211(wl);
1999 if (ret)
2000 goto out_platform;
2001
2002 ret = wl1271_register_hw(wl);
2003 if (ret)
2004 goto out_platform;
2005
2006 wl1271_debugfs_init(wl);
2007
2008 wl1271_notice("initialized");
2009
2010 return 0;
2011
2012 out_platform:
2013 platform_device_unregister(&wl1271_device);
2014
2015 out_irq:
2016 free_irq(wl->irq, wl);
2017
2018 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 ieee80211_free_hw(hw);
2020
2021 return ret;
2022}
2023
2024static int __devexit wl1271_remove(struct spi_device *spi)
2025{
2026 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2027
2028 ieee80211_unregister_hw(wl->hw);
2029
2030 wl1271_debugfs_exit(wl);
2031 platform_device_unregister(&wl1271_device);
2032 free_irq(wl->irq, wl);
2033 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002034 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035 wl->fw = NULL;
2036 kfree(wl->nvs);
2037 wl->nvs = NULL;
2038
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039 kfree(wl->fw_status);
2040 kfree(wl->tx_res_if);
2041
2042 ieee80211_free_hw(wl->hw);
2043
2044 return 0;
2045}
2046
2047
2048static struct spi_driver wl1271_spi_driver = {
2049 .driver = {
2050 .name = "wl1271",
2051 .bus = &spi_bus_type,
2052 .owner = THIS_MODULE,
2053 },
2054
2055 .probe = wl1271_probe,
2056 .remove = __devexit_p(wl1271_remove),
2057};
2058
2059static int __init wl1271_init(void)
2060{
2061 int ret;
2062
2063 ret = spi_register_driver(&wl1271_spi_driver);
2064 if (ret < 0) {
2065 wl1271_error("failed to register spi driver: %d", ret);
2066 goto out;
2067 }
2068
2069out:
2070 return ret;
2071}
2072
2073static void __exit wl1271_exit(void)
2074{
2075 spi_unregister_driver(&wl1271_spi_driver);
2076
2077 wl1271_notice("unloaded");
2078}
2079
2080module_init(wl1271_init);
2081module_exit(wl1271_exit);
2082
2083MODULE_LICENSE("GPL");
2084MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002085MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002086MODULE_FIRMWARE(WL1271_FW_NAME);