blob: 0795bf3c60da8c393f48d3941b3ad9187344fea4 [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
621 wl1271_power_on(wl);
622 msleep(WL1271_POWER_ON_SLEEP);
623 wl1271_spi_reset(wl);
624 wl1271_spi_init(wl);
625
626 /* We don't need a real memory partition here, because we only want
627 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300628 memset(&partition, 0, sizeof(partition));
629 partition.reg.start = REGISTERS_BASE;
630 partition.reg.size = REGISTERS_DOWN_SIZE;
631 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300632
633 /* ELP module wake up */
634 wl1271_fw_wakeup(wl);
635
636 /* whal_FwCtrl_BootSm() */
637
638 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300639 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640
641 /* 1. check if chip id is valid */
642
643 switch (wl->chip.id) {
644 case CHIP_ID_1271_PG10:
645 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
646 wl->chip.id);
647
648 ret = wl1271_setup(wl);
649 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200650 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 break;
652 case CHIP_ID_1271_PG20:
653 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
654 wl->chip.id);
655
656 ret = wl1271_setup(wl);
657 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200658 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659 break;
660 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200661 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 }
665
666 if (wl->fw == NULL) {
667 ret = wl1271_fetch_firmware(wl);
668 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 }
671
672 /* No NVS from netlink, try to get it from the filesystem */
673 if (wl->nvs == NULL) {
674 ret = wl1271_fetch_nvs(wl);
675 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200676 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 }
678
679out:
680 return ret;
681}
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683int wl1271_plt_start(struct wl1271 *wl)
684{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200685 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 int ret;
687
688 mutex_lock(&wl->mutex);
689
690 wl1271_notice("power up");
691
692 if (wl->state != WL1271_STATE_OFF) {
693 wl1271_error("cannot go into PLT state because not "
694 "in off state: %d", wl->state);
695 ret = -EBUSY;
696 goto out;
697 }
698
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200699 while (retries) {
700 retries--;
701 ret = wl1271_chip_wakeup(wl);
702 if (ret < 0)
703 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 ret = wl1271_boot(wl);
706 if (ret < 0)
707 goto power_off;
708
709 ret = wl1271_plt_init(wl);
710 if (ret < 0)
711 goto irq_disable;
712
713 /* Make sure power saving is disabled */
714 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
715 if (ret < 0)
716 goto irq_disable;
717
718 wl->state = WL1271_STATE_PLT;
719 wl1271_notice("firmware booted in PLT mode (%s)",
720 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 goto out;
722
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723irq_disable:
724 wl1271_disable_interrupts(wl);
725 mutex_unlock(&wl->mutex);
726 /* Unlocking the mutex in the middle of handling is
727 inherently unsafe. In this case we deem it safe to do,
728 because we need to let any possibly pending IRQ out of
729 the system (and while we are WL1271_STATE_OFF the IRQ
730 work function will not do anything.) Also, any other
731 possible concurrent operations will fail due to the
732 current state, hence the wl1271 struct should be safe. */
733 cancel_work_sync(&wl->irq_work);
734 mutex_lock(&wl->mutex);
735power_off:
736 wl1271_power_off(wl);
737 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200739 wl1271_error("firmware boot in PLT mode failed despite %d retries",
740 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741out:
742 mutex_unlock(&wl->mutex);
743
744 return ret;
745}
746
747int wl1271_plt_stop(struct wl1271 *wl)
748{
749 int ret = 0;
750
751 mutex_lock(&wl->mutex);
752
753 wl1271_notice("power down");
754
755 if (wl->state != WL1271_STATE_PLT) {
756 wl1271_error("cannot power down because not in PLT "
757 "state: %d", wl->state);
758 ret = -EBUSY;
759 goto out;
760 }
761
762 wl1271_disable_interrupts(wl);
763 wl1271_power_off(wl);
764
765 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300766 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767
768out:
769 mutex_unlock(&wl->mutex);
770
771 return ret;
772}
773
774
775static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
776{
777 struct wl1271 *wl = hw->priv;
778
779 skb_queue_tail(&wl->tx_queue, skb);
780
781 /*
782 * The chip specific setup must run before the first TX packet -
783 * before that, the tx_work will not be initialized!
784 */
785
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300786 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
788 /*
789 * The workqueue is slow to process the tx_queue and we need stop
790 * the queue here, otherwise the queue will get too long.
791 */
792 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
793 ieee80211_stop_queues(wl->hw);
794
795 /*
796 * FIXME: this is racy, the variable is not properly
797 * protected. Maybe fix this by removing the stupid
798 * variable altogether and checking the real queue state?
799 */
800 wl->tx_queue_stopped = true;
801 }
802
803 return NETDEV_TX_OK;
804}
805
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300806static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
807 void *arg)
808{
809 struct net_device *dev;
810 struct wireless_dev *wdev;
811 struct wiphy *wiphy;
812 struct ieee80211_hw *hw;
813 struct wl1271 *wl;
814 struct wl1271 *wl_temp;
815 struct in_device *idev;
816 struct in_ifaddr *ifa = arg;
817 int ret = 0;
818
819 /* FIXME: this ugly function should probably be implemented in the
820 * mac80211, and here should only be a simple callback handling actual
821 * setting of the filters. Now we need to dig up references to
822 * various structures to gain access to what we need.
823 * Also, because of this, there is no "initial" setting of the filter
824 * in "op_start", because we don't want to dig up struct net_device
825 * there - the filter will be set upon first change of the interface
826 * IP address. */
827
828 dev = ifa->ifa_dev->dev;
829
830 wdev = dev->ieee80211_ptr;
831 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200832 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300833
834 wiphy = wdev->wiphy;
835 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200836 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300837
838 hw = wiphy_priv(wiphy);
839 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200840 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300841
842 /* Check that the interface is one supported by this driver. */
843 wl_temp = hw->priv;
844 list_for_each_entry(wl, &wl_list, list) {
845 if (wl == wl_temp)
846 break;
847 }
848 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200849 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300850
851 /* Get the interface IP address for the device. "ifa" will become
852 NULL if:
853 - there is no IPV4 protocol address configured
854 - there are multiple (virtual) IPV4 addresses configured
855 When "ifa" is NULL, filtering will be disabled.
856 */
857 ifa = NULL;
858 idev = dev->ip_ptr;
859 if (idev)
860 ifa = idev->ifa_list;
861
862 if (ifa && ifa->ifa_next)
863 ifa = NULL;
864
865 mutex_lock(&wl->mutex);
866
867 if (wl->state == WL1271_STATE_OFF)
868 goto out;
869
870 ret = wl1271_ps_elp_wakeup(wl, false);
871 if (ret < 0)
872 goto out;
873 if (ifa)
874 ret = wl1271_acx_arp_ip_filter(wl, true,
875 (u8 *)&ifa->ifa_address,
876 ACX_IPV4_VERSION);
877 else
878 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
879 ACX_IPV4_VERSION);
880 wl1271_ps_elp_sleep(wl);
881
882out:
883 mutex_unlock(&wl->mutex);
884
Luciano Coelho17d72652009-11-23 23:22:15 +0200885 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300886}
887
888static struct notifier_block wl1271_dev_notifier = {
889 .notifier_call = wl1271_dev_notify,
890};
891
892
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893static int wl1271_op_start(struct ieee80211_hw *hw)
894{
895 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200896 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 int ret = 0;
898
899 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
900
901 mutex_lock(&wl->mutex);
902
903 if (wl->state != WL1271_STATE_OFF) {
904 wl1271_error("cannot start because not in off state: %d",
905 wl->state);
906 ret = -EBUSY;
907 goto out;
908 }
909
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200910 while (retries) {
911 retries--;
912 ret = wl1271_chip_wakeup(wl);
913 if (ret < 0)
914 goto power_off;
915
916 ret = wl1271_boot(wl);
917 if (ret < 0)
918 goto power_off;
919
920 ret = wl1271_hw_init(wl);
921 if (ret < 0)
922 goto irq_disable;
923
924 wl->state = WL1271_STATE_ON;
925 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 goto out;
927
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200928irq_disable:
929 wl1271_disable_interrupts(wl);
930 mutex_unlock(&wl->mutex);
931 /* Unlocking the mutex in the middle of handling is
932 inherently unsafe. In this case we deem it safe to do,
933 because we need to let any possibly pending IRQ out of
934 the system (and while we are WL1271_STATE_OFF the IRQ
935 work function will not do anything.) Also, any other
936 possible concurrent operations will fail due to the
937 current state, hence the wl1271 struct should be safe. */
938 cancel_work_sync(&wl->irq_work);
939 mutex_lock(&wl->mutex);
940power_off:
941 wl1271_power_off(wl);
942 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200944 wl1271_error("firmware boot failed despite %d retries",
945 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300946out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947 mutex_unlock(&wl->mutex);
948
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300949 if (!ret) {
950 list_add(&wl->list, &wl_list);
951 register_inetaddr_notifier(&wl1271_dev_notifier);
952 }
953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954 return ret;
955}
956
957static void wl1271_op_stop(struct ieee80211_hw *hw)
958{
959 struct wl1271 *wl = hw->priv;
960 int i;
961
962 wl1271_info("down");
963
964 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
965
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300966 unregister_inetaddr_notifier(&wl1271_dev_notifier);
967 list_del(&wl->list);
968
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 mutex_lock(&wl->mutex);
970
971 WARN_ON(wl->state != WL1271_STATE_ON);
972
973 if (wl->scanning) {
974 mutex_unlock(&wl->mutex);
975 ieee80211_scan_completed(wl->hw, true);
976 mutex_lock(&wl->mutex);
977 wl->scanning = false;
978 }
979
980 wl->state = WL1271_STATE_OFF;
981
982 wl1271_disable_interrupts(wl);
983
984 mutex_unlock(&wl->mutex);
985
986 cancel_work_sync(&wl->irq_work);
987 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988
989 mutex_lock(&wl->mutex);
990
991 /* let's notify MAC80211 about the remaining pending TX frames */
992 wl1271_tx_flush(wl);
993 wl1271_power_off(wl);
994
995 memset(wl->bssid, 0, ETH_ALEN);
996 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
997 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300999 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000
1001 wl->rx_counter = 0;
1002 wl->elp = false;
1003 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001004 wl->psm_entry_retry = 0;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001005 wl->associated = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 wl->tx_queue_stopped = false;
1007 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1008 wl->tx_blocks_available = 0;
1009 wl->tx_results_count = 0;
1010 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001011 wl->tx_security_last_seq = 0;
1012 wl->tx_security_seq_16 = 0;
1013 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014 wl->time_offset = 0;
1015 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001016 wl->joined = false;
1017
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 for (i = 0; i < NUM_TX_QUEUES; i++)
1019 wl->tx_blocks_freed[i] = 0;
1020
1021 wl1271_debugfs_reset(wl);
1022 mutex_unlock(&wl->mutex);
1023}
1024
1025static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1026 struct ieee80211_if_init_conf *conf)
1027{
1028 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 int ret = 0;
1030
John W. Linvillee5539bc2009-08-18 10:50:34 -04001031 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1032 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033
1034 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001035 if (wl->vif) {
1036 ret = -EBUSY;
1037 goto out;
1038 }
1039
1040 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
1042 switch (conf->type) {
1043 case NL80211_IFTYPE_STATION:
1044 wl->bss_type = BSS_TYPE_STA_BSS;
1045 break;
1046 case NL80211_IFTYPE_ADHOC:
1047 wl->bss_type = BSS_TYPE_IBSS;
1048 break;
1049 default:
1050 ret = -EOPNOTSUPP;
1051 goto out;
1052 }
1053
1054 /* FIXME: what if conf->mac_addr changes? */
1055
1056out:
1057 mutex_unlock(&wl->mutex);
1058 return ret;
1059}
1060
1061static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1062 struct ieee80211_if_init_conf *conf)
1063{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001064 struct wl1271 *wl = hw->priv;
1065
1066 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001068 wl->vif = NULL;
1069 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070}
1071
1072#if 0
1073static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1074 struct ieee80211_vif *vif,
1075 struct ieee80211_if_conf *conf)
1076{
1077 struct wl1271 *wl = hw->priv;
1078 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 int ret;
1080
David S. Miller32646902009-09-17 10:18:30 -07001081 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1082 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1084 conf->ssid_len);
1085
1086 mutex_lock(&wl->mutex);
1087
1088 ret = wl1271_ps_elp_wakeup(wl, false);
1089 if (ret < 0)
1090 goto out;
1091
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001092 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1093 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1094
1095 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1096
1097 ret = wl1271_cmd_join(wl);
1098 if (ret < 0)
1099 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001101 ret = wl1271_cmd_build_null_data(wl);
1102 if (ret < 0)
1103 goto out_sleep;
1104 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105
1106 wl->ssid_len = conf->ssid_len;
1107 if (wl->ssid_len)
1108 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110 if (conf->changed & IEEE80211_IFCC_BEACON) {
1111 beacon = ieee80211_beacon_get(hw, vif);
1112 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1113 beacon->data, beacon->len);
1114
1115 if (ret < 0) {
1116 dev_kfree_skb(beacon);
1117 goto out_sleep;
1118 }
1119
1120 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1121 beacon->data, beacon->len);
1122
1123 dev_kfree_skb(beacon);
1124
1125 if (ret < 0)
1126 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001127 }
1128
1129out_sleep:
1130 wl1271_ps_elp_sleep(wl);
1131
1132out:
1133 mutex_unlock(&wl->mutex);
1134
1135 return ret;
1136}
1137#endif
1138
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001139static int wl1271_join_channel(struct wl1271 *wl, int channel)
1140{
1141 int ret;
1142 /* we need to use a dummy BSSID for now */
1143 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1144 0xad, 0xbe, 0xef };
1145
1146 /* disable mac filter, so we hear everything */
1147 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1148
1149 wl->channel = channel;
1150 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1151
1152 ret = wl1271_cmd_join(wl);
1153 if (ret < 0)
1154 goto out;
1155
1156 wl->joined = true;
1157
1158out:
1159 return ret;
1160}
1161
1162static int wl1271_unjoin_channel(struct wl1271 *wl)
1163{
1164 int ret;
1165
1166 /* to stop listening to a channel, we disconnect */
1167 ret = wl1271_cmd_disconnect(wl);
1168 if (ret < 0)
1169 goto out;
1170
1171 wl->joined = false;
1172 wl->channel = 0;
1173 memset(wl->bssid, 0, ETH_ALEN);
1174 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1175
1176out:
1177 return ret;
1178}
1179
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001180static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1181{
1182 struct wl1271 *wl = hw->priv;
1183 struct ieee80211_conf *conf = &hw->conf;
1184 int channel, ret = 0;
1185
1186 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1187
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001188 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189 channel,
1190 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001191 conf->power_level,
1192 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001193
1194 mutex_lock(&wl->mutex);
1195
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001196 wl->band = conf->channel->band;
1197
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198 ret = wl1271_ps_elp_wakeup(wl, false);
1199 if (ret < 0)
1200 goto out;
1201
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001202 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1203 if (conf->flags & IEEE80211_CONF_IDLE && wl->joined)
1204 wl1271_unjoin_channel(wl);
1205 else
1206 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001207
1208 if (conf->flags & IEEE80211_CONF_IDLE) {
1209 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
1210 wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC);
1211 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212 }
1213
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001214 /* if the channel changes while joined, join again */
1215 if (channel != wl->channel && wl->joined)
1216 wl1271_join_channel(wl, channel);
1217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219 wl->psm_requested = true;
1220
1221 /*
1222 * We enter PSM only if we're already associated.
1223 * If we're not, we'll enter it when joining an SSID,
1224 * through the bss_info_changed() hook.
1225 */
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001226 if (wl->associated) {
1227 wl1271_info("psm enabled");
1228 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1229 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001230 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1231 wl->psm_requested) {
1232 wl1271_info("psm disabled");
1233
1234 wl->psm_requested = false;
1235
1236 if (wl->psm)
1237 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1238 }
1239
1240 if (conf->power_level != wl->power_level) {
1241 ret = wl1271_acx_tx_power(wl, conf->power_level);
1242 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001243 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244
1245 wl->power_level = conf->power_level;
1246 }
1247
1248out_sleep:
1249 wl1271_ps_elp_sleep(wl);
1250
1251out:
1252 mutex_unlock(&wl->mutex);
1253
1254 return ret;
1255}
1256
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001257struct wl1271_filter_params {
1258 bool enabled;
1259 int mc_list_length;
1260 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1261};
1262
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001263static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1264 struct dev_addr_list *mc_list)
1265{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001266 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001267 int i;
1268
Juuso Oikarinen74441132009-10-13 12:47:53 +03001269 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001270 if (!fp) {
1271 wl1271_error("Out of memory setting filters.");
1272 return 0;
1273 }
1274
1275 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001276 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001277 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1278 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001279 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001280 }
1281
1282 fp->mc_list_length = 0;
1283 for (i = 0; i < mc_count; i++) {
1284 if (mc_list->da_addrlen == ETH_ALEN) {
1285 memcpy(fp->mc_list[fp->mc_list_length],
1286 mc_list->da_addr, ETH_ALEN);
1287 fp->mc_list_length++;
1288 } else
1289 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001290 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001291 }
1292
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001293 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001294}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001296#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1297 FIF_ALLMULTI | \
1298 FIF_FCSFAIL | \
1299 FIF_BCN_PRBRESP_PROMISC | \
1300 FIF_CONTROL | \
1301 FIF_OTHER_BSS)
1302
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1304 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001305 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001307 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001309 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310
1311 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1312
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001313 mutex_lock(&wl->mutex);
1314
1315 if (wl->state == WL1271_STATE_OFF)
1316 goto out;
1317
1318 ret = wl1271_ps_elp_wakeup(wl, false);
1319 if (ret < 0)
1320 goto out;
1321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322 *total &= WL1271_SUPPORTED_FILTERS;
1323 changed &= WL1271_SUPPORTED_FILTERS;
1324
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001325 if (*total & FIF_ALLMULTI)
1326 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1327 else if (fp)
1328 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1329 fp->mc_list,
1330 fp->mc_list_length);
1331 if (ret < 0)
1332 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001334 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001335
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001336 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001337
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001338 /* determine, whether supported filter values have changed */
1339 if (changed == 0)
1340 goto out_sleep;
1341
1342 /* apply configured filters */
1343 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1344 if (ret < 0)
1345 goto out_sleep;
1346
1347out_sleep:
1348 wl1271_ps_elp_sleep(wl);
1349
1350out:
1351 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352}
1353
1354static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1355 struct ieee80211_vif *vif,
1356 struct ieee80211_sta *sta,
1357 struct ieee80211_key_conf *key_conf)
1358{
1359 struct wl1271 *wl = hw->priv;
1360 const u8 *addr;
1361 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001362 u32 tx_seq_32 = 0;
1363 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 u8 key_type;
1365
1366 static const u8 bcast_addr[ETH_ALEN] =
1367 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1368
1369 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1370
1371 addr = sta ? sta->addr : bcast_addr;
1372
1373 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1374 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1375 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1376 key_conf->alg, key_conf->keyidx,
1377 key_conf->keylen, key_conf->flags);
1378 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1379
1380 if (is_zero_ether_addr(addr)) {
1381 /* We dont support TX only encryption */
1382 ret = -EOPNOTSUPP;
1383 goto out;
1384 }
1385
1386 mutex_lock(&wl->mutex);
1387
1388 ret = wl1271_ps_elp_wakeup(wl, false);
1389 if (ret < 0)
1390 goto out_unlock;
1391
1392 switch (key_conf->alg) {
1393 case ALG_WEP:
1394 key_type = KEY_WEP;
1395
1396 key_conf->hw_key_idx = key_conf->keyidx;
1397 break;
1398 case ALG_TKIP:
1399 key_type = KEY_TKIP;
1400
1401 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001402 tx_seq_32 = wl->tx_security_seq_32;
1403 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404 break;
1405 case ALG_CCMP:
1406 key_type = KEY_AES;
1407
1408 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001409 tx_seq_32 = wl->tx_security_seq_32;
1410 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411 break;
1412 default:
1413 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1414
1415 ret = -EOPNOTSUPP;
1416 goto out_sleep;
1417 }
1418
1419 switch (cmd) {
1420 case SET_KEY:
1421 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1422 key_conf->keyidx, key_type,
1423 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001424 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 if (ret < 0) {
1426 wl1271_error("Could not add or replace key");
1427 goto out_sleep;
1428 }
1429 break;
1430
1431 case DISABLE_KEY:
1432 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1433 key_conf->keyidx, key_type,
1434 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001435 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436 if (ret < 0) {
1437 wl1271_error("Could not remove key");
1438 goto out_sleep;
1439 }
1440 break;
1441
1442 default:
1443 wl1271_error("Unsupported key cmd 0x%x", cmd);
1444 ret = -EOPNOTSUPP;
1445 goto out_sleep;
1446
1447 break;
1448 }
1449
1450out_sleep:
1451 wl1271_ps_elp_sleep(wl);
1452
1453out_unlock:
1454 mutex_unlock(&wl->mutex);
1455
1456out:
1457 return ret;
1458}
1459
1460static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1461 struct cfg80211_scan_request *req)
1462{
1463 struct wl1271 *wl = hw->priv;
1464 int ret;
1465 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001466 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467
1468 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1469
1470 if (req->n_ssids) {
1471 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001472 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473 }
1474
1475 mutex_lock(&wl->mutex);
1476
1477 ret = wl1271_ps_elp_wakeup(wl, false);
1478 if (ret < 0)
1479 goto out;
1480
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001481 if (wl1271_11a_enabled())
1482 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1483 WL1271_SCAN_BAND_DUAL, 3);
1484 else
1485 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1486 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487
1488 wl1271_ps_elp_sleep(wl);
1489
1490out:
1491 mutex_unlock(&wl->mutex);
1492
1493 return ret;
1494}
1495
1496static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1497{
1498 struct wl1271 *wl = hw->priv;
1499 int ret;
1500
1501 mutex_lock(&wl->mutex);
1502
1503 ret = wl1271_ps_elp_wakeup(wl, false);
1504 if (ret < 0)
1505 goto out;
1506
1507 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1508 if (ret < 0)
1509 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1510
1511 wl1271_ps_elp_sleep(wl);
1512
1513out:
1514 mutex_unlock(&wl->mutex);
1515
1516 return ret;
1517}
1518
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001519static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1520{
1521 struct ieee80211_supported_band *band;
1522 u32 enabled_rates = 0;
1523 int bit;
1524
1525 band = wl->hw->wiphy->bands[wl->band];
1526 for (bit = 0; bit < band->n_bitrates; bit++) {
1527 if (basic_rate_set & 0x1)
1528 enabled_rates |= band->bitrates[bit].hw_value;
1529 basic_rate_set >>= 1;
1530 }
1531
1532 return enabled_rates;
1533}
1534
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1536 struct ieee80211_vif *vif,
1537 struct ieee80211_bss_conf *bss_conf,
1538 u32 changed)
1539{
1540 enum wl1271_cmd_ps_mode mode;
1541 struct wl1271 *wl = hw->priv;
1542 int ret;
1543
1544 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1545
1546 mutex_lock(&wl->mutex);
1547
1548 ret = wl1271_ps_elp_wakeup(wl, false);
1549 if (ret < 0)
1550 goto out;
1551
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001552 if ((changed & BSS_CHANGED_BSSID) &&
1553 /*
1554 * Now we know the correct bssid, so we send a new join command
1555 * and enable the BSSID filter
1556 */
1557 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1558 wl->rx_config |= CFG_BSSID_FILTER_EN;
1559 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Luciano Coelhobdcbbb92009-12-11 15:40:48 +02001560 ret = wl1271_cmd_build_null_data(wl);
1561 if (ret < 0) {
1562 wl1271_warning("cmd buld null data failed %d",
1563 ret);
1564 goto out_sleep;
1565 }
Luciano Coelhocd264762009-12-11 15:40:47 +02001566 ret = wl1271_cmd_join(wl);
1567 if (ret < 0) {
1568 wl1271_warning("cmd join failed %d", ret);
1569 goto out_sleep;
1570 }
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001571 wl->joined = true;
1572 }
1573
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574 if (changed & BSS_CHANGED_ASSOC) {
1575 if (bss_conf->assoc) {
1576 wl->aid = bss_conf->aid;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001577 wl->associated = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001579 /*
1580 * with wl1271, we don't need to update the
1581 * beacon_int and dtim_period, because the firmware
1582 * updates it by itself when the first beacon is
1583 * received after a join.
1584 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1586 if (ret < 0)
1587 goto out_sleep;
1588
1589 ret = wl1271_acx_aid(wl, wl->aid);
1590 if (ret < 0)
1591 goto out_sleep;
1592
1593 /* If we want to go in PSM but we're not there yet */
1594 if (wl->psm_requested && !wl->psm) {
1595 mode = STATION_POWER_SAVE_MODE;
1596 ret = wl1271_ps_set_mode(wl, mode);
1597 if (ret < 0)
1598 goto out_sleep;
1599 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001600 } else {
1601 /* use defaults when not associated */
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001602 wl->associated = false;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001603 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001604 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001605
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001607
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 if (changed & BSS_CHANGED_ERP_SLOT) {
1609 if (bss_conf->use_short_slot)
1610 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1611 else
1612 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1613 if (ret < 0) {
1614 wl1271_warning("Set slot time failed %d", ret);
1615 goto out_sleep;
1616 }
1617 }
1618
1619 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1620 if (bss_conf->use_short_preamble)
1621 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1622 else
1623 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1624 }
1625
1626 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1627 if (bss_conf->use_cts_prot)
1628 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1629 else
1630 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1631 if (ret < 0) {
1632 wl1271_warning("Set ctsprotect failed %d", ret);
1633 goto out_sleep;
1634 }
1635 }
1636
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001637 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001638 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001639 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001640
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001641 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001642 if (ret < 0) {
1643 wl1271_warning("Set rate policies failed %d", ret);
1644 goto out_sleep;
1645 }
1646 }
1647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648out_sleep:
1649 wl1271_ps_elp_sleep(wl);
1650
1651out:
1652 mutex_unlock(&wl->mutex);
1653}
1654
1655
1656/* can't be const, mac80211 writes to this */
1657static struct ieee80211_rate wl1271_rates[] = {
1658 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001659 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1660 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001661 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001662 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1663 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1665 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001666 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1667 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1669 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001670 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1671 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001672 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1673 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001674 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1675 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001677 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1678 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001679 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001680 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1681 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001682 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001683 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1684 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001686 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1687 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001689 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1690 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001691 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001692 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1693 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001694 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001695 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1696 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697};
1698
1699/* can't be const, mac80211 writes to this */
1700static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001701 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1702 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1703 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1704 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1705 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1706 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1707 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1708 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1709 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1710 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1711 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1712 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1713 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714};
1715
1716/* can't be const, mac80211 writes to this */
1717static struct ieee80211_supported_band wl1271_band_2ghz = {
1718 .channels = wl1271_channels,
1719 .n_channels = ARRAY_SIZE(wl1271_channels),
1720 .bitrates = wl1271_rates,
1721 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1722};
1723
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001724/* 5 GHz data rates for WL1273 */
1725static struct ieee80211_rate wl1271_rates_5ghz[] = {
1726 { .bitrate = 60,
1727 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1728 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1729 { .bitrate = 90,
1730 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1731 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1732 { .bitrate = 120,
1733 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1734 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1735 { .bitrate = 180,
1736 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1737 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1738 { .bitrate = 240,
1739 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1740 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1741 { .bitrate = 360,
1742 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1743 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1744 { .bitrate = 480,
1745 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1746 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1747 { .bitrate = 540,
1748 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1749 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1750};
1751
1752/* 5 GHz band channels for WL1273 */
1753static struct ieee80211_channel wl1271_channels_5ghz[] = {
1754 { .hw_value = 183, .center_freq = 4915},
1755 { .hw_value = 184, .center_freq = 4920},
1756 { .hw_value = 185, .center_freq = 4925},
1757 { .hw_value = 187, .center_freq = 4935},
1758 { .hw_value = 188, .center_freq = 4940},
1759 { .hw_value = 189, .center_freq = 4945},
1760 { .hw_value = 192, .center_freq = 4960},
1761 { .hw_value = 196, .center_freq = 4980},
1762 { .hw_value = 7, .center_freq = 5035},
1763 { .hw_value = 8, .center_freq = 5040},
1764 { .hw_value = 9, .center_freq = 5045},
1765 { .hw_value = 11, .center_freq = 5055},
1766 { .hw_value = 12, .center_freq = 5060},
1767 { .hw_value = 16, .center_freq = 5080},
1768 { .hw_value = 34, .center_freq = 5170},
1769 { .hw_value = 36, .center_freq = 5180},
1770 { .hw_value = 38, .center_freq = 5190},
1771 { .hw_value = 40, .center_freq = 5200},
1772 { .hw_value = 42, .center_freq = 5210},
1773 { .hw_value = 44, .center_freq = 5220},
1774 { .hw_value = 46, .center_freq = 5230},
1775 { .hw_value = 48, .center_freq = 5240},
1776 { .hw_value = 52, .center_freq = 5260},
1777 { .hw_value = 56, .center_freq = 5280},
1778 { .hw_value = 60, .center_freq = 5300},
1779 { .hw_value = 64, .center_freq = 5320},
1780 { .hw_value = 100, .center_freq = 5500},
1781 { .hw_value = 104, .center_freq = 5520},
1782 { .hw_value = 108, .center_freq = 5540},
1783 { .hw_value = 112, .center_freq = 5560},
1784 { .hw_value = 116, .center_freq = 5580},
1785 { .hw_value = 120, .center_freq = 5600},
1786 { .hw_value = 124, .center_freq = 5620},
1787 { .hw_value = 128, .center_freq = 5640},
1788 { .hw_value = 132, .center_freq = 5660},
1789 { .hw_value = 136, .center_freq = 5680},
1790 { .hw_value = 140, .center_freq = 5700},
1791 { .hw_value = 149, .center_freq = 5745},
1792 { .hw_value = 153, .center_freq = 5765},
1793 { .hw_value = 157, .center_freq = 5785},
1794 { .hw_value = 161, .center_freq = 5805},
1795 { .hw_value = 165, .center_freq = 5825},
1796};
1797
1798
1799static struct ieee80211_supported_band wl1271_band_5ghz = {
1800 .channels = wl1271_channels_5ghz,
1801 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1802 .bitrates = wl1271_rates_5ghz,
1803 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1804};
1805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806static const struct ieee80211_ops wl1271_ops = {
1807 .start = wl1271_op_start,
1808 .stop = wl1271_op_stop,
1809 .add_interface = wl1271_op_add_interface,
1810 .remove_interface = wl1271_op_remove_interface,
1811 .config = wl1271_op_config,
1812/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001813 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 .configure_filter = wl1271_op_configure_filter,
1815 .tx = wl1271_op_tx,
1816 .set_key = wl1271_op_set_key,
1817 .hw_scan = wl1271_op_hw_scan,
1818 .bss_info_changed = wl1271_op_bss_info_changed,
1819 .set_rts_threshold = wl1271_op_set_rts_threshold,
1820};
1821
1822static int wl1271_register_hw(struct wl1271 *wl)
1823{
1824 int ret;
1825
1826 if (wl->mac80211_registered)
1827 return 0;
1828
1829 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1830
1831 ret = ieee80211_register_hw(wl->hw);
1832 if (ret < 0) {
1833 wl1271_error("unable to register mac80211 hw: %d", ret);
1834 return ret;
1835 }
1836
1837 wl->mac80211_registered = true;
1838
1839 wl1271_notice("loaded");
1840
1841 return 0;
1842}
1843
1844static int wl1271_init_ieee80211(struct wl1271 *wl)
1845{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001846 /* The tx descriptor buffer and the TKIP space. */
1847 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1848 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849
1850 /* unit us */
1851 /* FIXME: find a proper value */
1852 wl->hw->channel_change_time = 10000;
1853
1854 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001855 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001856 IEEE80211_HW_BEACON_FILTER |
1857 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001858
1859 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
1860 wl->hw->wiphy->max_scan_ssids = 1;
1861 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1862
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001863 if (wl1271_11a_enabled())
1864 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1865
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1867
1868 return 0;
1869}
1870
1871static void wl1271_device_release(struct device *dev)
1872{
1873
1874}
1875
1876static struct platform_device wl1271_device = {
1877 .name = "wl1271",
1878 .id = -1,
1879
1880 /* device model insists to have a release function */
1881 .dev = {
1882 .release = wl1271_device_release,
1883 },
1884};
1885
1886#define WL1271_DEFAULT_CHANNEL 0
1887static int __devinit wl1271_probe(struct spi_device *spi)
1888{
1889 struct wl12xx_platform_data *pdata;
1890 struct ieee80211_hw *hw;
1891 struct wl1271 *wl;
1892 int ret, i;
1893 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1894
1895 pdata = spi->dev.platform_data;
1896 if (!pdata) {
1897 wl1271_error("no platform data");
1898 return -ENODEV;
1899 }
1900
1901 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1902 if (!hw) {
1903 wl1271_error("could not alloc ieee80211_hw");
1904 return -ENOMEM;
1905 }
1906
1907 wl = hw->priv;
1908 memset(wl, 0, sizeof(*wl));
1909
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001910 INIT_LIST_HEAD(&wl->list);
1911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912 wl->hw = hw;
1913 dev_set_drvdata(&spi->dev, wl);
1914 wl->spi = spi;
1915
1916 skb_queue_head_init(&wl->tx_queue);
1917
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001918 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919 wl->channel = WL1271_DEFAULT_CHANNEL;
1920 wl->scanning = false;
1921 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001922 wl->rx_counter = 0;
1923 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1924 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1925 wl->elp = false;
1926 wl->psm = 0;
1927 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001928 wl->psm_entry_retry = 0;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001929 wl->associated = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930 wl->tx_queue_stopped = false;
1931 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001932 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001933 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001934 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001935 wl->joined = false;
Luciano Coelho98b2a682009-12-11 15:40:52 +02001936 wl->gpio_power = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001938 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939 wl->tx_frames[i] = NULL;
1940
1941 spin_lock_init(&wl->wl_lock);
1942
1943 /*
1944 * In case our MAC address is not correctly set,
1945 * we use a random but Nokia MAC.
1946 */
1947 memcpy(wl->mac_addr, nokia_oui, 3);
1948 get_random_bytes(wl->mac_addr + 3, 3);
1949
1950 wl->state = WL1271_STATE_OFF;
1951 mutex_init(&wl->mutex);
1952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 /* This is the only SPI value that we need to set here, the rest
1954 * comes from the board-peripherals file */
1955 spi->bits_per_word = 32;
1956
1957 ret = spi_setup(spi);
1958 if (ret < 0) {
1959 wl1271_error("spi_setup failed");
1960 goto out_free;
1961 }
1962
1963 wl->set_power = pdata->set_power;
1964 if (!wl->set_power) {
1965 wl1271_error("set power function missing in platform data");
1966 ret = -ENODEV;
1967 goto out_free;
1968 }
1969
1970 wl->irq = spi->irq;
1971 if (wl->irq < 0) {
1972 wl1271_error("irq missing in platform data");
1973 ret = -ENODEV;
1974 goto out_free;
1975 }
1976
1977 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
1978 if (ret < 0) {
1979 wl1271_error("request_irq() failed: %d", ret);
1980 goto out_free;
1981 }
1982
1983 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
1984
1985 disable_irq(wl->irq);
1986
1987 ret = platform_device_register(&wl1271_device);
1988 if (ret) {
1989 wl1271_error("couldn't register platform device");
1990 goto out_irq;
1991 }
1992 dev_set_drvdata(&wl1271_device.dev, wl);
1993
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001994 /* Apply default driver configuration. */
1995 wl1271_conf_init(wl);
1996
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 ret = wl1271_init_ieee80211(wl);
1998 if (ret)
1999 goto out_platform;
2000
2001 ret = wl1271_register_hw(wl);
2002 if (ret)
2003 goto out_platform;
2004
2005 wl1271_debugfs_init(wl);
2006
2007 wl1271_notice("initialized");
2008
2009 return 0;
2010
2011 out_platform:
2012 platform_device_unregister(&wl1271_device);
2013
2014 out_irq:
2015 free_irq(wl->irq, wl);
2016
2017 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 ieee80211_free_hw(hw);
2019
2020 return ret;
2021}
2022
2023static int __devexit wl1271_remove(struct spi_device *spi)
2024{
2025 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2026
2027 ieee80211_unregister_hw(wl->hw);
2028
2029 wl1271_debugfs_exit(wl);
2030 platform_device_unregister(&wl1271_device);
2031 free_irq(wl->irq, wl);
2032 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002033 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034 wl->fw = NULL;
2035 kfree(wl->nvs);
2036 wl->nvs = NULL;
2037
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038 kfree(wl->fw_status);
2039 kfree(wl->tx_res_if);
2040
2041 ieee80211_free_hw(wl->hw);
2042
2043 return 0;
2044}
2045
2046
2047static struct spi_driver wl1271_spi_driver = {
2048 .driver = {
2049 .name = "wl1271",
2050 .bus = &spi_bus_type,
2051 .owner = THIS_MODULE,
2052 },
2053
2054 .probe = wl1271_probe,
2055 .remove = __devexit_p(wl1271_remove),
2056};
2057
2058static int __init wl1271_init(void)
2059{
2060 int ret;
2061
2062 ret = spi_register_driver(&wl1271_spi_driver);
2063 if (ret < 0) {
2064 wl1271_error("failed to register spi driver: %d", ret);
2065 goto out;
2066 }
2067
2068out:
2069 return ret;
2070}
2071
2072static void __exit wl1271_exit(void)
2073{
2074 spi_unregister_driver(&wl1271_spi_driver);
2075
2076 wl1271_notice("unloaded");
2077}
2078
2079module_init(wl1271_init);
2080module_exit(wl1271_exit);
2081
2082MODULE_LICENSE("GPL");
2083MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002084MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002085MODULE_FIRMWARE(WL1271_FW_NAME);