blob: 6f026fe63d7fea9230230dff54bd3500c181e692 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/interrupt.h>
27#include <linux/firmware.h>
28#include <linux/delay.h>
29#include <linux/irq.h>
30#include <linux/spi/spi.h>
31#include <linux/crc32.h>
32#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030033#include <linux/vmalloc.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034#include <linux/spi/wl12xx.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030035#include <linux/inetdevice.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
37#include "wl1271.h"
38#include "wl12xx_80211.h"
39#include "wl1271_reg.h"
40#include "wl1271_spi.h"
41#include "wl1271_event.h"
42#include "wl1271_tx.h"
43#include "wl1271_rx.h"
44#include "wl1271_ps.h"
45#include "wl1271_init.h"
46#include "wl1271_debugfs.h"
47#include "wl1271_cmd.h"
48#include "wl1271_boot.h"
49
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
54 .per_threshold = 7500,
55 .max_scan_compensation_time = 120000,
56 .nfs_sample_interval = 400,
57 .load_ratio = 50,
58 .auto_ps_mode = 0,
59 .probe_req_compensation = 170,
60 .scan_window_compensation = 50,
61 .antenna_config = 0,
62 .beacon_miss_threshold = 60,
63 .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
64 .rate_adaptation_snr = 0
65 },
66 .rx = {
67 .rx_msdu_life_time = 512000,
68 .packet_detection_threshold = 0,
69 .ps_poll_timeout = 15,
70 .upsd_timeout = 15,
71 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +020072 .rx_cca_threshold = 0,
73 .irq_blk_threshold = 0xFFFF,
74 .irq_pkt_threshold = 0,
75 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030076 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
77 },
78 .tx = {
79 .tx_energy_detection = 0,
80 .rc_conf = {
Juuso Oikarinenec078d92009-12-11 15:41:05 +020081 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
82 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +030083 .short_retry_limit = 10,
84 .long_retry_limit = 10,
85 .aflags = 0
86 },
87 .ac_conf_count = 4,
88 .ac_conf = {
89 [0] = {
90 .ac = CONF_TX_AC_BE,
91 .cw_min = 15,
92 .cw_max = 63,
93 .aifsn = 3,
94 .tx_op_limit = 0,
95 },
96 [1] = {
97 .ac = CONF_TX_AC_BK,
98 .cw_min = 15,
99 .cw_max = 63,
100 .aifsn = 7,
101 .tx_op_limit = 0,
102 },
103 [2] = {
104 .ac = CONF_TX_AC_VI,
105 .cw_min = 15,
106 .cw_max = 63,
107 .aifsn = CONF_TX_AIFS_PIFS,
108 .tx_op_limit = 3008,
109 },
110 [3] = {
111 .ac = CONF_TX_AC_VO,
112 .cw_min = 15,
113 .cw_max = 63,
114 .aifsn = CONF_TX_AIFS_PIFS,
115 .tx_op_limit = 1504,
116 },
117 },
118 .tid_conf_count = 7,
119 .tid_conf = {
120 [0] = {
121 .queue_id = 0,
122 .channel_type = CONF_CHANNEL_TYPE_DCF,
123 .tsid = CONF_TX_AC_BE,
124 .ps_scheme = CONF_PS_SCHEME_LEGACY,
125 .ack_policy = CONF_ACK_POLICY_LEGACY,
126 .apsd_conf = {0, 0},
127 },
128 [1] = {
129 .queue_id = 1,
130 .channel_type = CONF_CHANNEL_TYPE_DCF,
131 .tsid = CONF_TX_AC_BE,
132 .ps_scheme = CONF_PS_SCHEME_LEGACY,
133 .ack_policy = CONF_ACK_POLICY_LEGACY,
134 .apsd_conf = {0, 0},
135 },
136 [2] = {
137 .queue_id = 2,
138 .channel_type = CONF_CHANNEL_TYPE_DCF,
139 .tsid = CONF_TX_AC_BE,
140 .ps_scheme = CONF_PS_SCHEME_LEGACY,
141 .ack_policy = CONF_ACK_POLICY_LEGACY,
142 .apsd_conf = {0, 0},
143 },
144 [3] = {
145 .queue_id = 3,
146 .channel_type = CONF_CHANNEL_TYPE_DCF,
147 .tsid = CONF_TX_AC_BE,
148 .ps_scheme = CONF_PS_SCHEME_LEGACY,
149 .ack_policy = CONF_ACK_POLICY_LEGACY,
150 .apsd_conf = {0, 0},
151 },
152 [4] = {
153 .queue_id = 4,
154 .channel_type = CONF_CHANNEL_TYPE_DCF,
155 .tsid = CONF_TX_AC_BE,
156 .ps_scheme = CONF_PS_SCHEME_LEGACY,
157 .ack_policy = CONF_ACK_POLICY_LEGACY,
158 .apsd_conf = {0, 0},
159 },
160 [5] = {
161 .queue_id = 5,
162 .channel_type = CONF_CHANNEL_TYPE_DCF,
163 .tsid = CONF_TX_AC_BE,
164 .ps_scheme = CONF_PS_SCHEME_LEGACY,
165 .ack_policy = CONF_ACK_POLICY_LEGACY,
166 .apsd_conf = {0, 0},
167 },
168 [6] = {
169 .queue_id = 6,
170 .channel_type = CONF_CHANNEL_TYPE_DCF,
171 .tsid = CONF_TX_AC_BE,
172 .ps_scheme = CONF_PS_SCHEME_LEGACY,
173 .ack_policy = CONF_ACK_POLICY_LEGACY,
174 .apsd_conf = {0, 0},
175 }
176 },
177 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200178 .tx_compl_timeout = 700,
179 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .conn = {
182 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
183 .listen_interval = 0,
184 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
185 .bcn_filt_ie_count = 1,
186 .bcn_filt_ie = {
187 [0] = {
188 .ie = WLAN_EID_CHANNEL_SWITCH,
189 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
190 }
191 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200192 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300193 .bss_lose_timeout = 100,
194 .beacon_rx_timeout = 10000,
195 .broadcast_timeout = 20000,
196 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200197 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .sig_trigger_count = 2,
199 .sig_trigger = {
200 [0] = {
201 .threshold = -75,
202 .pacing = 500,
203 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
204 .type = CONF_TRIG_EVENT_TYPE_EDGE,
205 .direction = CONF_TRIG_EVENT_DIR_LOW,
206 .hysteresis = 2,
207 .index = 0,
208 .enable = 1
209 },
210 [1] = {
211 .threshold = -75,
212 .pacing = 500,
213 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
214 .type = CONF_TRIG_EVENT_TYPE_EDGE,
215 .direction = CONF_TRIG_EVENT_DIR_HIGH,
216 .hysteresis = 2,
217 .index = 1,
218 .enable = 1
219 }
220 },
221 .sig_weights = {
222 .rssi_bcn_avg_weight = 10,
223 .rssi_pkt_avg_weight = 10,
224 .snr_bcn_avg_weight = 10,
225 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300226 },
227 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200228 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200229 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 },
231 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .genparam = {
Luciano Coelhoc7c8adb2009-11-23 23:22:19 +0200233 .ref_clk = CONF_REF_CLK_38_4_E,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300234 .settling_time = 5,
235 .clk_valid_on_wakeup = 0,
236 .dc2dcmode = 0,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300237 .single_dual_band = CONF_SINGLE_BAND,
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200238 .tx_bip_fem_autodetect = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300239 .tx_bip_fem_manufacturer = 1,
240 .settings = 1,
Luciano Coelho76c0f8d2009-12-11 15:40:41 +0200241 .sr_state = 1,
Juuso Oikarinen149e3872009-12-11 15:40:56 +0200242 .srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
243 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
244 .srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
245 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
246 .srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
247 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
Luciano Coelho76c0f8d2009-12-11 15:40:41 +0200248 .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0 },
250 .sr_sen_n_p = 0,
251 .sr_sen_n_p_gain = 0,
252 .sr_sen_nrn = 0,
253 .sr_sen_prn = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300254 },
255 .radioparam = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200256 .rx_trace_loss = 0x24,
257 .tx_trace_loss = 0x0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300258 .rx_rssi_and_proc_compens = {
259 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
Luciano Coelho1b38ea82009-12-11 15:40:51 +0200260 0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 0x00, 0x0a, 0x14 },
262 .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
263 .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
264 .rx_rssi_and_proc_compens_5 = {
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00 },
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200268 .tx_ref_pd_voltage = 0x1a9,
269 .tx_ref_power = 0x80,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 .tx_offset_db = 0x0,
271 .tx_rate_limits_normal = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200272 0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300273 .tx_rate_limits_degraded = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200274 0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
Luciano Coelhocf18be42009-12-11 15:40:43 +0200275 .tx_rate_limits_extreme = {
276 0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300277 .tx_channel_limits_11b = {
278 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
279 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
280 0x22, 0x50 },
281 .tx_channel_limits_ofdm = {
282 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
283 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
284 0x20, 0x50 },
285 .tx_pdv_rate_offsets = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200286 0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300287 .tx_ibias = {
Luciano Coelhoa3e84842009-12-11 15:40:42 +0200288 0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
289 .rx_fem_insertion_loss = 0x0e,
Luciano Coelhocf18be42009-12-11 15:40:43 +0200290 .degraded_low_to_normal_threshold = 0x1e,
291 .degraded_normal_to_high_threshold = 0x2d,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300292 .tx_ref_pd_voltage_5 = {
293 0x0190, 0x01a4, 0x01c3, 0x01d8,
294 0x020a, 0x021c },
295 .tx_ref_power_5 = {
296 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
297 .tx_offset_db_5 = {
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300299 .tx_rate_limits_normal_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300300 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300301 .tx_rate_limits_degraded_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300302 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Luciano Coelhocf18be42009-12-11 15:40:43 +0200303 .tx_rate_limits_extreme_5 = {
304 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300305 .tx_channel_limits_ofdm_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300306 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, 0x50, 0x50, 0x50, 0x50, 0x50,
310 0x50, 0x50, 0x50 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300311 .tx_pdv_rate_offsets_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300312 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300313 .tx_ibias_5 = {
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300314 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
315 .rx_fem_insertion_loss_5 = {
Luciano Coelhocf18be42009-12-11 15:40:43 +0200316 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
317 .degraded_low_to_normal_threshold_5 = 0x00,
318 .degraded_normal_to_high_threshold_5 = 0x00
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300319 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200320 },
321 .itrim = {
322 .enable = false,
323 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200324 },
325 .pm_config = {
326 .host_clk_settling_time = 5000,
327 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300328 }
329};
330
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300331static LIST_HEAD(wl_list);
332
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300333static void wl1271_conf_init(struct wl1271 *wl)
334{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300335
336 /*
337 * This function applies the default configuration to the driver. This
338 * function is invoked upon driver load (spi probe.)
339 *
340 * The configuration is stored in a run-time structure in order to
341 * facilitate for run-time adjustment of any of the parameters. Making
342 * changes to the configuration structure will apply the new values on
343 * the next interface up (wl1271_op_start.)
344 */
345
346 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300347 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300348
349 if (wl1271_11a_enabled())
350 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300351}
352
353
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300354static int wl1271_plt_init(struct wl1271 *wl)
355{
356 int ret;
357
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200358 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200359 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200360 return ret;
361
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200362 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200363 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200364 return ret;
365
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300366 ret = wl1271_acx_init_mem_config(wl);
367 if (ret < 0)
368 return ret;
369
Luciano Coelho94210892009-12-11 15:40:55 +0200370 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300371 if (ret < 0)
372 return ret;
373
374 return 0;
375}
376
377static void wl1271_disable_interrupts(struct wl1271 *wl)
378{
379 disable_irq(wl->irq);
380}
381
382static void wl1271_power_off(struct wl1271 *wl)
383{
384 wl->set_power(false);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200385 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300386}
387
388static void wl1271_power_on(struct wl1271 *wl)
389{
390 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200391 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300392}
393
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300394static void wl1271_fw_status(struct wl1271 *wl,
395 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300396{
397 u32 total = 0;
398 int i;
399
Juuso Oikarinen74621412009-10-12 15:08:54 +0300400 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
401 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300402
403 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
404 "drv_rx_counter = %d, tx_results_counter = %d)",
405 status->intr,
406 status->fw_rx_counter,
407 status->drv_rx_counter,
408 status->tx_results_counter);
409
410 /* update number of available TX blocks */
411 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300412 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
413 wl->tx_blocks_freed[i];
414
415 wl->tx_blocks_freed[i] =
416 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300417 wl->tx_blocks_available += cnt;
418 total += cnt;
419 }
420
421 /* if more blocks are available now, schedule some tx work */
422 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300423 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424
425 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300426 wl->time_offset = jiffies_to_usecs(jiffies) -
427 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300428}
429
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430static void wl1271_irq_work(struct work_struct *work)
431{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300433 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300434 struct wl1271 *wl =
435 container_of(work, struct wl1271, irq_work);
436
437 mutex_lock(&wl->mutex);
438
439 wl1271_debug(DEBUG_IRQ, "IRQ work");
440
441 if (wl->state == WL1271_STATE_OFF)
442 goto out;
443
444 ret = wl1271_ps_elp_wakeup(wl, true);
445 if (ret < 0)
446 goto out;
447
Juuso Oikarinen74621412009-10-12 15:08:54 +0300448 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300450 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300451 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300452 if (!intr) {
453 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
454 goto out_sleep;
455 }
456
457 intr &= WL1271_INTR_MASK;
458
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300459 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300460 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200461 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300462 }
463
464 if (intr & WL1271_ACX_INTR_EVENT_B) {
465 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200466 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300467 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300469 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
470 wl1271_debug(DEBUG_IRQ,
471 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300473 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
474 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300475
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300476 if (intr & WL1271_ACX_INTR_DATA) {
477 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
478 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300479
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300480 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300482 /* check for tx results */
483 if (tx_res_cnt)
484 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300485
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300486 wl1271_rx(wl, wl->fw_status);
487 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300488
489out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300490 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300491 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492 wl1271_ps_elp_sleep(wl);
493
494out:
495 mutex_unlock(&wl->mutex);
496}
497
498static irqreturn_t wl1271_irq(int irq, void *cookie)
499{
500 struct wl1271 *wl;
501 unsigned long flags;
502
503 wl1271_debug(DEBUG_IRQ, "IRQ");
504
505 wl = cookie;
506
507 /* complete the ELP completion */
508 spin_lock_irqsave(&wl->wl_lock, flags);
509 if (wl->elp_compl) {
510 complete(wl->elp_compl);
511 wl->elp_compl = NULL;
512 }
513
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300514 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300515 spin_unlock_irqrestore(&wl->wl_lock, flags);
516
517 return IRQ_HANDLED;
518}
519
520static int wl1271_fetch_firmware(struct wl1271 *wl)
521{
522 const struct firmware *fw;
523 int ret;
524
525 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
526
527 if (ret < 0) {
528 wl1271_error("could not get firmware: %d", ret);
529 return ret;
530 }
531
532 if (fw->size % 4) {
533 wl1271_error("firmware size is not multiple of 32 bits: %zu",
534 fw->size);
535 ret = -EILSEQ;
536 goto out;
537 }
538
539 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300540 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300541
542 if (!wl->fw) {
543 wl1271_error("could not allocate memory for the firmware");
544 ret = -ENOMEM;
545 goto out;
546 }
547
548 memcpy(wl->fw, fw->data, wl->fw_len);
549
550 ret = 0;
551
552out:
553 release_firmware(fw);
554
555 return ret;
556}
557
558static int wl1271_fetch_nvs(struct wl1271 *wl)
559{
560 const struct firmware *fw;
561 int ret;
562
563 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
564
565 if (ret < 0) {
566 wl1271_error("could not get nvs file: %d", ret);
567 return ret;
568 }
569
570 if (fw->size % 4) {
571 wl1271_error("nvs size is not multiple of 32 bits: %zu",
572 fw->size);
573 ret = -EILSEQ;
574 goto out;
575 }
576
577 wl->nvs_len = fw->size;
578 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
579
580 if (!wl->nvs) {
581 wl1271_error("could not allocate memory for the nvs file");
582 ret = -ENOMEM;
583 goto out;
584 }
585
586 memcpy(wl->nvs, fw->data, wl->nvs_len);
587
588 ret = 0;
589
590out:
591 release_firmware(fw);
592
593 return ret;
594}
595
596static void wl1271_fw_wakeup(struct wl1271 *wl)
597{
598 u32 elp_reg;
599
600 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300601 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300602}
603
604static int wl1271_setup(struct wl1271 *wl)
605{
606 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
607 if (!wl->fw_status)
608 return -ENOMEM;
609
610 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
611 if (!wl->tx_res_if) {
612 kfree(wl->fw_status);
613 return -ENOMEM;
614 }
615
616 INIT_WORK(&wl->irq_work, wl1271_irq_work);
617 INIT_WORK(&wl->tx_work, wl1271_tx_work);
618 return 0;
619}
620
621static int wl1271_chip_wakeup(struct wl1271 *wl)
622{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300623 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300624 int ret = 0;
625
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200626 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627 wl1271_power_on(wl);
628 msleep(WL1271_POWER_ON_SLEEP);
629 wl1271_spi_reset(wl);
630 wl1271_spi_init(wl);
631
632 /* We don't need a real memory partition here, because we only want
633 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300634 memset(&partition, 0, sizeof(partition));
635 partition.reg.start = REGISTERS_BASE;
636 partition.reg.size = REGISTERS_DOWN_SIZE;
637 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638
639 /* ELP module wake up */
640 wl1271_fw_wakeup(wl);
641
642 /* whal_FwCtrl_BootSm() */
643
644 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300645 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646
647 /* 1. check if chip id is valid */
648
649 switch (wl->chip.id) {
650 case CHIP_ID_1271_PG10:
651 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
652 wl->chip.id);
653
654 ret = wl1271_setup(wl);
655 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200656 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657 break;
658 case CHIP_ID_1271_PG20:
659 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
660 wl->chip.id);
661
662 ret = wl1271_setup(wl);
663 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200664 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 break;
666 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200667 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300668 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 }
671
672 if (wl->fw == NULL) {
673 ret = wl1271_fetch_firmware(wl);
674 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200675 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676 }
677
678 /* No NVS from netlink, try to get it from the filesystem */
679 if (wl->nvs == NULL) {
680 ret = wl1271_fetch_nvs(wl);
681 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200682 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 }
684
685out:
686 return ret;
687}
688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689int wl1271_plt_start(struct wl1271 *wl)
690{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200691 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692 int ret;
693
694 mutex_lock(&wl->mutex);
695
696 wl1271_notice("power up");
697
698 if (wl->state != WL1271_STATE_OFF) {
699 wl1271_error("cannot go into PLT state because not "
700 "in off state: %d", wl->state);
701 ret = -EBUSY;
702 goto out;
703 }
704
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 while (retries) {
706 retries--;
707 ret = wl1271_chip_wakeup(wl);
708 if (ret < 0)
709 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200711 ret = wl1271_boot(wl);
712 if (ret < 0)
713 goto power_off;
714
715 ret = wl1271_plt_init(wl);
716 if (ret < 0)
717 goto irq_disable;
718
719 /* Make sure power saving is disabled */
720 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
721 if (ret < 0)
722 goto irq_disable;
723
724 wl->state = WL1271_STATE_PLT;
725 wl1271_notice("firmware booted in PLT mode (%s)",
726 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727 goto out;
728
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200729irq_disable:
730 wl1271_disable_interrupts(wl);
731 mutex_unlock(&wl->mutex);
732 /* Unlocking the mutex in the middle of handling is
733 inherently unsafe. In this case we deem it safe to do,
734 because we need to let any possibly pending IRQ out of
735 the system (and while we are WL1271_STATE_OFF the IRQ
736 work function will not do anything.) Also, any other
737 possible concurrent operations will fail due to the
738 current state, hence the wl1271 struct should be safe. */
739 cancel_work_sync(&wl->irq_work);
740 mutex_lock(&wl->mutex);
741power_off:
742 wl1271_power_off(wl);
743 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200745 wl1271_error("firmware boot in PLT mode failed despite %d retries",
746 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747out:
748 mutex_unlock(&wl->mutex);
749
750 return ret;
751}
752
753int wl1271_plt_stop(struct wl1271 *wl)
754{
755 int ret = 0;
756
757 mutex_lock(&wl->mutex);
758
759 wl1271_notice("power down");
760
761 if (wl->state != WL1271_STATE_PLT) {
762 wl1271_error("cannot power down because not in PLT "
763 "state: %d", wl->state);
764 ret = -EBUSY;
765 goto out;
766 }
767
768 wl1271_disable_interrupts(wl);
769 wl1271_power_off(wl);
770
771 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300772 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773
774out:
775 mutex_unlock(&wl->mutex);
776
777 return ret;
778}
779
780
781static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
782{
783 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200784 struct ieee80211_conf *conf = &hw->conf;
785 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
786 struct ieee80211_sta *sta = txinfo->control.sta;
787 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200789 /* peek into the rates configured in the STA entry */
790 spin_lock_irqsave(&wl->wl_lock, flags);
791 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
792 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
793 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
794 }
795 spin_unlock_irqrestore(&wl->wl_lock, flags);
796
797 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300798 skb_queue_tail(&wl->tx_queue, skb);
799
800 /*
801 * The chip specific setup must run before the first TX packet -
802 * before that, the tx_work will not be initialized!
803 */
804
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300805 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806
807 /*
808 * The workqueue is slow to process the tx_queue and we need stop
809 * the queue here, otherwise the queue will get too long.
810 */
811 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
812 ieee80211_stop_queues(wl->hw);
813
814 /*
815 * FIXME: this is racy, the variable is not properly
816 * protected. Maybe fix this by removing the stupid
817 * variable altogether and checking the real queue state?
818 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200819 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820 }
821
822 return NETDEV_TX_OK;
823}
824
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300825static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
826 void *arg)
827{
828 struct net_device *dev;
829 struct wireless_dev *wdev;
830 struct wiphy *wiphy;
831 struct ieee80211_hw *hw;
832 struct wl1271 *wl;
833 struct wl1271 *wl_temp;
834 struct in_device *idev;
835 struct in_ifaddr *ifa = arg;
836 int ret = 0;
837
838 /* FIXME: this ugly function should probably be implemented in the
839 * mac80211, and here should only be a simple callback handling actual
840 * setting of the filters. Now we need to dig up references to
841 * various structures to gain access to what we need.
842 * Also, because of this, there is no "initial" setting of the filter
843 * in "op_start", because we don't want to dig up struct net_device
844 * there - the filter will be set upon first change of the interface
845 * IP address. */
846
847 dev = ifa->ifa_dev->dev;
848
849 wdev = dev->ieee80211_ptr;
850 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200851 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300852
853 wiphy = wdev->wiphy;
854 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200855 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300856
857 hw = wiphy_priv(wiphy);
858 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200859 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300860
861 /* Check that the interface is one supported by this driver. */
862 wl_temp = hw->priv;
863 list_for_each_entry(wl, &wl_list, list) {
864 if (wl == wl_temp)
865 break;
866 }
867 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200868 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300869
870 /* Get the interface IP address for the device. "ifa" will become
871 NULL if:
872 - there is no IPV4 protocol address configured
873 - there are multiple (virtual) IPV4 addresses configured
874 When "ifa" is NULL, filtering will be disabled.
875 */
876 ifa = NULL;
877 idev = dev->ip_ptr;
878 if (idev)
879 ifa = idev->ifa_list;
880
881 if (ifa && ifa->ifa_next)
882 ifa = NULL;
883
884 mutex_lock(&wl->mutex);
885
886 if (wl->state == WL1271_STATE_OFF)
887 goto out;
888
889 ret = wl1271_ps_elp_wakeup(wl, false);
890 if (ret < 0)
891 goto out;
892 if (ifa)
893 ret = wl1271_acx_arp_ip_filter(wl, true,
894 (u8 *)&ifa->ifa_address,
895 ACX_IPV4_VERSION);
896 else
897 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
898 ACX_IPV4_VERSION);
899 wl1271_ps_elp_sleep(wl);
900
901out:
902 mutex_unlock(&wl->mutex);
903
Luciano Coelho17d72652009-11-23 23:22:15 +0200904 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300905}
906
907static struct notifier_block wl1271_dev_notifier = {
908 .notifier_call = wl1271_dev_notify,
909};
910
911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912static int wl1271_op_start(struct ieee80211_hw *hw)
913{
914 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200915 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300916 int ret = 0;
917
918 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
919
920 mutex_lock(&wl->mutex);
921
922 if (wl->state != WL1271_STATE_OFF) {
923 wl1271_error("cannot start because not in off state: %d",
924 wl->state);
925 ret = -EBUSY;
926 goto out;
927 }
928
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200929 while (retries) {
930 retries--;
931 ret = wl1271_chip_wakeup(wl);
932 if (ret < 0)
933 goto power_off;
934
935 ret = wl1271_boot(wl);
936 if (ret < 0)
937 goto power_off;
938
939 ret = wl1271_hw_init(wl);
940 if (ret < 0)
941 goto irq_disable;
942
943 wl->state = WL1271_STATE_ON;
944 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 goto out;
946
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200947irq_disable:
948 wl1271_disable_interrupts(wl);
949 mutex_unlock(&wl->mutex);
950 /* Unlocking the mutex in the middle of handling is
951 inherently unsafe. In this case we deem it safe to do,
952 because we need to let any possibly pending IRQ out of
953 the system (and while we are WL1271_STATE_OFF the IRQ
954 work function will not do anything.) Also, any other
955 possible concurrent operations will fail due to the
956 current state, hence the wl1271 struct should be safe. */
957 cancel_work_sync(&wl->irq_work);
958 mutex_lock(&wl->mutex);
959power_off:
960 wl1271_power_off(wl);
961 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200963 wl1271_error("firmware boot failed despite %d retries",
964 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300965out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 mutex_unlock(&wl->mutex);
967
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300968 if (!ret) {
969 list_add(&wl->list, &wl_list);
970 register_inetaddr_notifier(&wl1271_dev_notifier);
971 }
972
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 return ret;
974}
975
976static void wl1271_op_stop(struct ieee80211_hw *hw)
977{
978 struct wl1271 *wl = hw->priv;
979 int i;
980
981 wl1271_info("down");
982
983 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
984
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300985 unregister_inetaddr_notifier(&wl1271_dev_notifier);
986 list_del(&wl->list);
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 mutex_lock(&wl->mutex);
989
990 WARN_ON(wl->state != WL1271_STATE_ON);
991
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200992 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 mutex_unlock(&wl->mutex);
994 ieee80211_scan_completed(wl->hw, true);
995 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996 }
997
998 wl->state = WL1271_STATE_OFF;
999
1000 wl1271_disable_interrupts(wl);
1001
1002 mutex_unlock(&wl->mutex);
1003
1004 cancel_work_sync(&wl->irq_work);
1005 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006
1007 mutex_lock(&wl->mutex);
1008
1009 /* let's notify MAC80211 about the remaining pending TX frames */
1010 wl1271_tx_flush(wl);
1011 wl1271_power_off(wl);
1012
1013 memset(wl->bssid, 0, ETH_ALEN);
1014 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1015 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001017 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
1019 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001020 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1022 wl->tx_blocks_available = 0;
1023 wl->tx_results_count = 0;
1024 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001025 wl->tx_security_last_seq = 0;
1026 wl->tx_security_seq_16 = 0;
1027 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 wl->time_offset = 0;
1029 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001030 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1031 wl->sta_rate_set = 0;
1032 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001033
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 for (i = 0; i < NUM_TX_QUEUES; i++)
1035 wl->tx_blocks_freed[i] = 0;
1036
1037 wl1271_debugfs_reset(wl);
1038 mutex_unlock(&wl->mutex);
1039}
1040
1041static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001042 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043{
1044 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 int ret = 0;
1046
John W. Linvillee5539bc2009-08-18 10:50:34 -04001047 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001048 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049
1050 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001051 if (wl->vif) {
1052 ret = -EBUSY;
1053 goto out;
1054 }
1055
Johannes Berg1ed32e42009-12-23 13:15:45 +01001056 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057
Johannes Berg1ed32e42009-12-23 13:15:45 +01001058 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059 case NL80211_IFTYPE_STATION:
1060 wl->bss_type = BSS_TYPE_STA_BSS;
1061 break;
1062 case NL80211_IFTYPE_ADHOC:
1063 wl->bss_type = BSS_TYPE_IBSS;
1064 break;
1065 default:
1066 ret = -EOPNOTSUPP;
1067 goto out;
1068 }
1069
1070 /* FIXME: what if conf->mac_addr changes? */
1071
1072out:
1073 mutex_unlock(&wl->mutex);
1074 return ret;
1075}
1076
1077static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001078 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001080 struct wl1271 *wl = hw->priv;
1081
1082 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001084 wl->vif = NULL;
1085 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086}
1087
1088#if 0
1089static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1090 struct ieee80211_vif *vif,
1091 struct ieee80211_if_conf *conf)
1092{
1093 struct wl1271 *wl = hw->priv;
1094 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 int ret;
1096
David S. Miller32646902009-09-17 10:18:30 -07001097 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1098 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1100 conf->ssid_len);
1101
1102 mutex_lock(&wl->mutex);
1103
1104 ret = wl1271_ps_elp_wakeup(wl, false);
1105 if (ret < 0)
1106 goto out;
1107
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001108 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1109 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1110
1111 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1112
1113 ret = wl1271_cmd_join(wl);
1114 if (ret < 0)
1115 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001117 ret = wl1271_cmd_build_null_data(wl);
1118 if (ret < 0)
1119 goto out_sleep;
1120 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121
1122 wl->ssid_len = conf->ssid_len;
1123 if (wl->ssid_len)
1124 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1125
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126 if (conf->changed & IEEE80211_IFCC_BEACON) {
1127 beacon = ieee80211_beacon_get(hw, vif);
1128 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1129 beacon->data, beacon->len);
1130
1131 if (ret < 0) {
1132 dev_kfree_skb(beacon);
1133 goto out_sleep;
1134 }
1135
1136 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1137 beacon->data, beacon->len);
1138
1139 dev_kfree_skb(beacon);
1140
1141 if (ret < 0)
1142 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143 }
1144
1145out_sleep:
1146 wl1271_ps_elp_sleep(wl);
1147
1148out:
1149 mutex_unlock(&wl->mutex);
1150
1151 return ret;
1152}
1153#endif
1154
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001155static int wl1271_join_channel(struct wl1271 *wl, int channel)
1156{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001157 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001158 /* we need to use a dummy BSSID for now */
1159 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1160 0xad, 0xbe, 0xef };
1161
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001162 /* the dummy join is not required for ad-hoc */
1163 if (wl->bss_type == BSS_TYPE_IBSS)
1164 goto out;
1165
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001166 /* disable mac filter, so we hear everything */
1167 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1168
1169 wl->channel = channel;
1170 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1171
1172 ret = wl1271_cmd_join(wl);
1173 if (ret < 0)
1174 goto out;
1175
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001176 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001177
1178out:
1179 return ret;
1180}
1181
1182static int wl1271_unjoin_channel(struct wl1271 *wl)
1183{
1184 int ret;
1185
1186 /* to stop listening to a channel, we disconnect */
1187 ret = wl1271_cmd_disconnect(wl);
1188 if (ret < 0)
1189 goto out;
1190
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001191 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001192 wl->channel = 0;
1193 memset(wl->bssid, 0, ETH_ALEN);
1194 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1195
1196out:
1197 return ret;
1198}
1199
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001200static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1201{
1202 struct wl1271 *wl = hw->priv;
1203 struct ieee80211_conf *conf = &hw->conf;
1204 int channel, ret = 0;
1205
1206 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1207
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209 channel,
1210 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001211 conf->power_level,
1212 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213
1214 mutex_lock(&wl->mutex);
1215
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001216 wl->band = conf->channel->band;
1217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 ret = wl1271_ps_elp_wakeup(wl, false);
1219 if (ret < 0)
1220 goto out;
1221
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001222 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001223 if (conf->flags & IEEE80211_CONF_IDLE &&
1224 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001225 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001226 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001227 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001228
1229 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001230 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1231 wl->sta_rate_set = 0;
1232 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001233 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234 }
1235
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001236 /* if the channel changes while joined, join again */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001237 if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001238 wl1271_join_channel(wl, channel);
1239
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001240 if (conf->flags & IEEE80211_CONF_PS &&
1241 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1242 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243
1244 /*
1245 * We enter PSM only if we're already associated.
1246 * If we're not, we'll enter it when joining an SSID,
1247 * through the bss_info_changed() hook.
1248 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001249 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001250 wl1271_info("psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001251 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1252 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001253 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001255 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256 wl1271_info("psm disabled");
1257
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001258 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001260 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001261 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1262 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263 }
1264
1265 if (conf->power_level != wl->power_level) {
1266 ret = wl1271_acx_tx_power(wl, conf->power_level);
1267 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001268 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
1270 wl->power_level = conf->power_level;
1271 }
1272
1273out_sleep:
1274 wl1271_ps_elp_sleep(wl);
1275
1276out:
1277 mutex_unlock(&wl->mutex);
1278
1279 return ret;
1280}
1281
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001282struct wl1271_filter_params {
1283 bool enabled;
1284 int mc_list_length;
1285 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1286};
1287
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001288static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1289 struct dev_addr_list *mc_list)
1290{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001291 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001292 int i;
1293
Juuso Oikarinen74441132009-10-13 12:47:53 +03001294 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001295 if (!fp) {
1296 wl1271_error("Out of memory setting filters.");
1297 return 0;
1298 }
1299
1300 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001301 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001302 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1303 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001304 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001305 }
1306
1307 fp->mc_list_length = 0;
1308 for (i = 0; i < mc_count; i++) {
1309 if (mc_list->da_addrlen == ETH_ALEN) {
1310 memcpy(fp->mc_list[fp->mc_list_length],
1311 mc_list->da_addr, ETH_ALEN);
1312 fp->mc_list_length++;
1313 } else
1314 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001315 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001316 }
1317
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001318 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001319}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001321#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1322 FIF_ALLMULTI | \
1323 FIF_FCSFAIL | \
1324 FIF_BCN_PRBRESP_PROMISC | \
1325 FIF_CONTROL | \
1326 FIF_OTHER_BSS)
1327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1329 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001330 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001332 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001334 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335
1336 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1337
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001338 mutex_lock(&wl->mutex);
1339
1340 if (wl->state == WL1271_STATE_OFF)
1341 goto out;
1342
1343 ret = wl1271_ps_elp_wakeup(wl, false);
1344 if (ret < 0)
1345 goto out;
1346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 *total &= WL1271_SUPPORTED_FILTERS;
1348 changed &= WL1271_SUPPORTED_FILTERS;
1349
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001350 if (*total & FIF_ALLMULTI)
1351 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1352 else if (fp)
1353 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1354 fp->mc_list,
1355 fp->mc_list_length);
1356 if (ret < 0)
1357 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001359 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001360
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001361 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001362
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 /* determine, whether supported filter values have changed */
1364 if (changed == 0)
1365 goto out_sleep;
1366
1367 /* apply configured filters */
1368 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1369 if (ret < 0)
1370 goto out_sleep;
1371
1372out_sleep:
1373 wl1271_ps_elp_sleep(wl);
1374
1375out:
1376 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377}
1378
1379static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1380 struct ieee80211_vif *vif,
1381 struct ieee80211_sta *sta,
1382 struct ieee80211_key_conf *key_conf)
1383{
1384 struct wl1271 *wl = hw->priv;
1385 const u8 *addr;
1386 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001387 u32 tx_seq_32 = 0;
1388 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389 u8 key_type;
1390
1391 static const u8 bcast_addr[ETH_ALEN] =
1392 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1393
1394 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1395
1396 addr = sta ? sta->addr : bcast_addr;
1397
1398 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1399 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1400 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1401 key_conf->alg, key_conf->keyidx,
1402 key_conf->keylen, key_conf->flags);
1403 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1404
1405 if (is_zero_ether_addr(addr)) {
1406 /* We dont support TX only encryption */
1407 ret = -EOPNOTSUPP;
1408 goto out;
1409 }
1410
1411 mutex_lock(&wl->mutex);
1412
1413 ret = wl1271_ps_elp_wakeup(wl, false);
1414 if (ret < 0)
1415 goto out_unlock;
1416
1417 switch (key_conf->alg) {
1418 case ALG_WEP:
1419 key_type = KEY_WEP;
1420
1421 key_conf->hw_key_idx = key_conf->keyidx;
1422 break;
1423 case ALG_TKIP:
1424 key_type = KEY_TKIP;
1425
1426 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001427 tx_seq_32 = wl->tx_security_seq_32;
1428 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 break;
1430 case ALG_CCMP:
1431 key_type = KEY_AES;
1432
1433 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001434 tx_seq_32 = wl->tx_security_seq_32;
1435 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436 break;
1437 default:
1438 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1439
1440 ret = -EOPNOTSUPP;
1441 goto out_sleep;
1442 }
1443
1444 switch (cmd) {
1445 case SET_KEY:
1446 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1447 key_conf->keyidx, key_type,
1448 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001449 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 if (ret < 0) {
1451 wl1271_error("Could not add or replace key");
1452 goto out_sleep;
1453 }
1454 break;
1455
1456 case DISABLE_KEY:
1457 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1458 key_conf->keyidx, key_type,
1459 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001460 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 if (ret < 0) {
1462 wl1271_error("Could not remove key");
1463 goto out_sleep;
1464 }
1465 break;
1466
1467 default:
1468 wl1271_error("Unsupported key cmd 0x%x", cmd);
1469 ret = -EOPNOTSUPP;
1470 goto out_sleep;
1471
1472 break;
1473 }
1474
1475out_sleep:
1476 wl1271_ps_elp_sleep(wl);
1477
1478out_unlock:
1479 mutex_unlock(&wl->mutex);
1480
1481out:
1482 return ret;
1483}
1484
1485static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1486 struct cfg80211_scan_request *req)
1487{
1488 struct wl1271 *wl = hw->priv;
1489 int ret;
1490 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001491 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492
1493 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1494
1495 if (req->n_ssids) {
1496 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001497 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 }
1499
1500 mutex_lock(&wl->mutex);
1501
1502 ret = wl1271_ps_elp_wakeup(wl, false);
1503 if (ret < 0)
1504 goto out;
1505
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001506 if (wl1271_11a_enabled())
1507 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1508 WL1271_SCAN_BAND_DUAL, 3);
1509 else
1510 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1511 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512
1513 wl1271_ps_elp_sleep(wl);
1514
1515out:
1516 mutex_unlock(&wl->mutex);
1517
1518 return ret;
1519}
1520
1521static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1522{
1523 struct wl1271 *wl = hw->priv;
1524 int ret;
1525
1526 mutex_lock(&wl->mutex);
1527
1528 ret = wl1271_ps_elp_wakeup(wl, false);
1529 if (ret < 0)
1530 goto out;
1531
1532 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1533 if (ret < 0)
1534 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1535
1536 wl1271_ps_elp_sleep(wl);
1537
1538out:
1539 mutex_unlock(&wl->mutex);
1540
1541 return ret;
1542}
1543
1544static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1545 struct ieee80211_vif *vif,
1546 struct ieee80211_bss_conf *bss_conf,
1547 u32 changed)
1548{
1549 enum wl1271_cmd_ps_mode mode;
1550 struct wl1271 *wl = hw->priv;
1551 int ret;
1552
1553 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1554
1555 mutex_lock(&wl->mutex);
1556
1557 ret = wl1271_ps_elp_wakeup(wl, false);
1558 if (ret < 0)
1559 goto out;
1560
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001561 if ((changed & BSS_CHANGED_BSSID) &&
1562 /*
1563 * Now we know the correct bssid, so we send a new join command
1564 * and enable the BSSID filter
1565 */
1566 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1567 wl->rx_config |= CFG_BSSID_FILTER_EN;
1568 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Luciano Coelhobdcbbb92009-12-11 15:40:48 +02001569 ret = wl1271_cmd_build_null_data(wl);
1570 if (ret < 0) {
1571 wl1271_warning("cmd buld null data failed %d",
1572 ret);
1573 goto out_sleep;
1574 }
Luciano Coelhocd264762009-12-11 15:40:47 +02001575 ret = wl1271_cmd_join(wl);
1576 if (ret < 0) {
1577 wl1271_warning("cmd join failed %d", ret);
1578 goto out_sleep;
1579 }
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001580 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001581 }
1582
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001583 if (wl->bss_type == BSS_TYPE_IBSS) {
1584 /* FIXME: This implements rudimentary ad-hoc support -
1585 proper templates are on the wish list and notification
1586 on when they change. This patch will update the templates
1587 on every call to this function. Also, the firmware will not
1588 answer to probe-requests as it does not have the proper
1589 SSID set in the JOIN command. The probe-response template
1590 is set nevertheless, as the FW will ASSERT without it */
1591 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1592
1593 if (beacon) {
1594 struct ieee80211_hdr *hdr;
1595 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1596 beacon->data,
1597 beacon->len);
1598
1599 if (ret < 0) {
1600 dev_kfree_skb(beacon);
1601 goto out_sleep;
1602 }
1603
1604 hdr = (struct ieee80211_hdr *) beacon->data;
1605 hdr->frame_control = cpu_to_le16(
1606 IEEE80211_FTYPE_MGMT |
1607 IEEE80211_STYPE_PROBE_RESP);
1608
1609 ret = wl1271_cmd_template_set(wl,
1610 CMD_TEMPL_PROBE_RESPONSE,
1611 beacon->data,
1612 beacon->len);
1613 dev_kfree_skb(beacon);
1614 if (ret < 0)
1615 goto out_sleep;
1616 }
1617 }
1618
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 if (changed & BSS_CHANGED_ASSOC) {
1620 if (bss_conf->assoc) {
1621 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001622 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001623
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001624 /*
1625 * with wl1271, we don't need to update the
1626 * beacon_int and dtim_period, because the firmware
1627 * updates it by itself when the first beacon is
1628 * received after a join.
1629 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001630 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1631 if (ret < 0)
1632 goto out_sleep;
1633
1634 ret = wl1271_acx_aid(wl, wl->aid);
1635 if (ret < 0)
1636 goto out_sleep;
1637
1638 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001639 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1640 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001641 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001642 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001643 if (ret < 0)
1644 goto out_sleep;
1645 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001646 } else {
1647 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001648 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001649 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001652 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 if (changed & BSS_CHANGED_ERP_SLOT) {
1655 if (bss_conf->use_short_slot)
1656 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1657 else
1658 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1659 if (ret < 0) {
1660 wl1271_warning("Set slot time failed %d", ret);
1661 goto out_sleep;
1662 }
1663 }
1664
1665 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1666 if (bss_conf->use_short_preamble)
1667 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1668 else
1669 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1670 }
1671
1672 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1673 if (bss_conf->use_cts_prot)
1674 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1675 else
1676 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1677 if (ret < 0) {
1678 wl1271_warning("Set ctsprotect failed %d", ret);
1679 goto out_sleep;
1680 }
1681 }
1682
1683out_sleep:
1684 wl1271_ps_elp_sleep(wl);
1685
1686out:
1687 mutex_unlock(&wl->mutex);
1688}
1689
1690
1691/* can't be const, mac80211 writes to this */
1692static struct ieee80211_rate wl1271_rates[] = {
1693 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001694 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1695 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001697 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1698 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1700 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001701 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1702 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001703 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1704 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001705 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1706 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1708 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001709 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1710 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001711 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001712 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1713 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001715 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1716 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001718 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1719 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001721 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1722 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001724 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1725 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001727 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1728 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001730 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1731 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001732};
1733
1734/* can't be const, mac80211 writes to this */
1735static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001736 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1737 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1738 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1739 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1740 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1741 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1742 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1743 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1744 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1745 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1746 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1747 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1748 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001749};
1750
1751/* can't be const, mac80211 writes to this */
1752static struct ieee80211_supported_band wl1271_band_2ghz = {
1753 .channels = wl1271_channels,
1754 .n_channels = ARRAY_SIZE(wl1271_channels),
1755 .bitrates = wl1271_rates,
1756 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1757};
1758
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001759/* 5 GHz data rates for WL1273 */
1760static struct ieee80211_rate wl1271_rates_5ghz[] = {
1761 { .bitrate = 60,
1762 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1763 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1764 { .bitrate = 90,
1765 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1766 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1767 { .bitrate = 120,
1768 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1769 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1770 { .bitrate = 180,
1771 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1772 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1773 { .bitrate = 240,
1774 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1775 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1776 { .bitrate = 360,
1777 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1778 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1779 { .bitrate = 480,
1780 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1781 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1782 { .bitrate = 540,
1783 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1784 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1785};
1786
1787/* 5 GHz band channels for WL1273 */
1788static struct ieee80211_channel wl1271_channels_5ghz[] = {
1789 { .hw_value = 183, .center_freq = 4915},
1790 { .hw_value = 184, .center_freq = 4920},
1791 { .hw_value = 185, .center_freq = 4925},
1792 { .hw_value = 187, .center_freq = 4935},
1793 { .hw_value = 188, .center_freq = 4940},
1794 { .hw_value = 189, .center_freq = 4945},
1795 { .hw_value = 192, .center_freq = 4960},
1796 { .hw_value = 196, .center_freq = 4980},
1797 { .hw_value = 7, .center_freq = 5035},
1798 { .hw_value = 8, .center_freq = 5040},
1799 { .hw_value = 9, .center_freq = 5045},
1800 { .hw_value = 11, .center_freq = 5055},
1801 { .hw_value = 12, .center_freq = 5060},
1802 { .hw_value = 16, .center_freq = 5080},
1803 { .hw_value = 34, .center_freq = 5170},
1804 { .hw_value = 36, .center_freq = 5180},
1805 { .hw_value = 38, .center_freq = 5190},
1806 { .hw_value = 40, .center_freq = 5200},
1807 { .hw_value = 42, .center_freq = 5210},
1808 { .hw_value = 44, .center_freq = 5220},
1809 { .hw_value = 46, .center_freq = 5230},
1810 { .hw_value = 48, .center_freq = 5240},
1811 { .hw_value = 52, .center_freq = 5260},
1812 { .hw_value = 56, .center_freq = 5280},
1813 { .hw_value = 60, .center_freq = 5300},
1814 { .hw_value = 64, .center_freq = 5320},
1815 { .hw_value = 100, .center_freq = 5500},
1816 { .hw_value = 104, .center_freq = 5520},
1817 { .hw_value = 108, .center_freq = 5540},
1818 { .hw_value = 112, .center_freq = 5560},
1819 { .hw_value = 116, .center_freq = 5580},
1820 { .hw_value = 120, .center_freq = 5600},
1821 { .hw_value = 124, .center_freq = 5620},
1822 { .hw_value = 128, .center_freq = 5640},
1823 { .hw_value = 132, .center_freq = 5660},
1824 { .hw_value = 136, .center_freq = 5680},
1825 { .hw_value = 140, .center_freq = 5700},
1826 { .hw_value = 149, .center_freq = 5745},
1827 { .hw_value = 153, .center_freq = 5765},
1828 { .hw_value = 157, .center_freq = 5785},
1829 { .hw_value = 161, .center_freq = 5805},
1830 { .hw_value = 165, .center_freq = 5825},
1831};
1832
1833
1834static struct ieee80211_supported_band wl1271_band_5ghz = {
1835 .channels = wl1271_channels_5ghz,
1836 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1837 .bitrates = wl1271_rates_5ghz,
1838 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1839};
1840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841static const struct ieee80211_ops wl1271_ops = {
1842 .start = wl1271_op_start,
1843 .stop = wl1271_op_stop,
1844 .add_interface = wl1271_op_add_interface,
1845 .remove_interface = wl1271_op_remove_interface,
1846 .config = wl1271_op_config,
1847/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001848 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 .configure_filter = wl1271_op_configure_filter,
1850 .tx = wl1271_op_tx,
1851 .set_key = wl1271_op_set_key,
1852 .hw_scan = wl1271_op_hw_scan,
1853 .bss_info_changed = wl1271_op_bss_info_changed,
1854 .set_rts_threshold = wl1271_op_set_rts_threshold,
1855};
1856
1857static int wl1271_register_hw(struct wl1271 *wl)
1858{
1859 int ret;
1860
1861 if (wl->mac80211_registered)
1862 return 0;
1863
1864 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1865
1866 ret = ieee80211_register_hw(wl->hw);
1867 if (ret < 0) {
1868 wl1271_error("unable to register mac80211 hw: %d", ret);
1869 return ret;
1870 }
1871
1872 wl->mac80211_registered = true;
1873
1874 wl1271_notice("loaded");
1875
1876 return 0;
1877}
1878
1879static int wl1271_init_ieee80211(struct wl1271 *wl)
1880{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001881 /* The tx descriptor buffer and the TKIP space. */
1882 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1883 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001884
1885 /* unit us */
1886 /* FIXME: find a proper value */
1887 wl->hw->channel_change_time = 10000;
1888
1889 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001890 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001891 IEEE80211_HW_BEACON_FILTER |
1892 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001893
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001894 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1895 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 wl->hw->wiphy->max_scan_ssids = 1;
1897 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1898
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001899 if (wl1271_11a_enabled())
1900 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1903
1904 return 0;
1905}
1906
1907static void wl1271_device_release(struct device *dev)
1908{
1909
1910}
1911
1912static struct platform_device wl1271_device = {
1913 .name = "wl1271",
1914 .id = -1,
1915
1916 /* device model insists to have a release function */
1917 .dev = {
1918 .release = wl1271_device_release,
1919 },
1920};
1921
1922#define WL1271_DEFAULT_CHANNEL 0
1923static int __devinit wl1271_probe(struct spi_device *spi)
1924{
1925 struct wl12xx_platform_data *pdata;
1926 struct ieee80211_hw *hw;
1927 struct wl1271 *wl;
1928 int ret, i;
1929 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1930
1931 pdata = spi->dev.platform_data;
1932 if (!pdata) {
1933 wl1271_error("no platform data");
1934 return -ENODEV;
1935 }
1936
1937 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1938 if (!hw) {
1939 wl1271_error("could not alloc ieee80211_hw");
1940 return -ENOMEM;
1941 }
1942
1943 wl = hw->priv;
1944 memset(wl, 0, sizeof(*wl));
1945
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001946 INIT_LIST_HEAD(&wl->list);
1947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 wl->hw = hw;
1949 dev_set_drvdata(&spi->dev, wl);
1950 wl->spi = spi;
1951
1952 skb_queue_head_init(&wl->tx_queue);
1953
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001954 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957 wl->rx_counter = 0;
1958 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1959 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001960 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001962 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001963 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1964 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001965 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001966 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001967 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001969 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 wl->tx_frames[i] = NULL;
1971
1972 spin_lock_init(&wl->wl_lock);
1973
1974 /*
1975 * In case our MAC address is not correctly set,
1976 * we use a random but Nokia MAC.
1977 */
1978 memcpy(wl->mac_addr, nokia_oui, 3);
1979 get_random_bytes(wl->mac_addr + 3, 3);
1980
1981 wl->state = WL1271_STATE_OFF;
1982 mutex_init(&wl->mutex);
1983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984 /* This is the only SPI value that we need to set here, the rest
1985 * comes from the board-peripherals file */
1986 spi->bits_per_word = 32;
1987
1988 ret = spi_setup(spi);
1989 if (ret < 0) {
1990 wl1271_error("spi_setup failed");
1991 goto out_free;
1992 }
1993
1994 wl->set_power = pdata->set_power;
1995 if (!wl->set_power) {
1996 wl1271_error("set power function missing in platform data");
1997 ret = -ENODEV;
1998 goto out_free;
1999 }
2000
2001 wl->irq = spi->irq;
2002 if (wl->irq < 0) {
2003 wl1271_error("irq missing in platform data");
2004 ret = -ENODEV;
2005 goto out_free;
2006 }
2007
2008 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2009 if (ret < 0) {
2010 wl1271_error("request_irq() failed: %d", ret);
2011 goto out_free;
2012 }
2013
2014 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2015
2016 disable_irq(wl->irq);
2017
2018 ret = platform_device_register(&wl1271_device);
2019 if (ret) {
2020 wl1271_error("couldn't register platform device");
2021 goto out_irq;
2022 }
2023 dev_set_drvdata(&wl1271_device.dev, wl);
2024
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002025 /* Apply default driver configuration. */
2026 wl1271_conf_init(wl);
2027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028 ret = wl1271_init_ieee80211(wl);
2029 if (ret)
2030 goto out_platform;
2031
2032 ret = wl1271_register_hw(wl);
2033 if (ret)
2034 goto out_platform;
2035
2036 wl1271_debugfs_init(wl);
2037
2038 wl1271_notice("initialized");
2039
2040 return 0;
2041
2042 out_platform:
2043 platform_device_unregister(&wl1271_device);
2044
2045 out_irq:
2046 free_irq(wl->irq, wl);
2047
2048 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 ieee80211_free_hw(hw);
2050
2051 return ret;
2052}
2053
2054static int __devexit wl1271_remove(struct spi_device *spi)
2055{
2056 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2057
2058 ieee80211_unregister_hw(wl->hw);
2059
2060 wl1271_debugfs_exit(wl);
2061 platform_device_unregister(&wl1271_device);
2062 free_irq(wl->irq, wl);
2063 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002064 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 wl->fw = NULL;
2066 kfree(wl->nvs);
2067 wl->nvs = NULL;
2068
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069 kfree(wl->fw_status);
2070 kfree(wl->tx_res_if);
2071
2072 ieee80211_free_hw(wl->hw);
2073
2074 return 0;
2075}
2076
2077
2078static struct spi_driver wl1271_spi_driver = {
2079 .driver = {
2080 .name = "wl1271",
2081 .bus = &spi_bus_type,
2082 .owner = THIS_MODULE,
2083 },
2084
2085 .probe = wl1271_probe,
2086 .remove = __devexit_p(wl1271_remove),
2087};
2088
2089static int __init wl1271_init(void)
2090{
2091 int ret;
2092
2093 ret = spi_register_driver(&wl1271_spi_driver);
2094 if (ret < 0) {
2095 wl1271_error("failed to register spi driver: %d", ret);
2096 goto out;
2097 }
2098
2099out:
2100 return ret;
2101}
2102
2103static void __exit wl1271_exit(void)
2104{
2105 spi_unregister_driver(&wl1271_spi_driver);
2106
2107 wl1271_notice("unloaded");
2108}
2109
2110module_init(wl1271_init);
2111module_exit(wl1271_exit);
2112
2113MODULE_LICENSE("GPL");
2114MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002115MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002116MODULE_FIRMWARE(WL1271_FW_NAME);