blob: 7a73aaadd04cb4db797129da402c66040df024d8 [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 Oikarinen8a080482009-10-13 12:47:44 +0300324 }
325};
326
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300327static LIST_HEAD(wl_list);
328
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300329static void wl1271_conf_init(struct wl1271 *wl)
330{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300331
332 /*
333 * This function applies the default configuration to the driver. This
334 * function is invoked upon driver load (spi probe.)
335 *
336 * The configuration is stored in a run-time structure in order to
337 * facilitate for run-time adjustment of any of the parameters. Making
338 * changes to the configuration structure will apply the new values on
339 * the next interface up (wl1271_op_start.)
340 */
341
342 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300343 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +0300344
345 if (wl1271_11a_enabled())
346 wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300347}
348
349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300350static int wl1271_plt_init(struct wl1271 *wl)
351{
352 int ret;
353
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200354 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200355 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200356 return ret;
357
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200358 ret = wl1271_cmd_radio_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 Coelhof5fc0f82009-08-06 16:25:28 +0300362 ret = wl1271_acx_init_mem_config(wl);
363 if (ret < 0)
364 return ret;
365
Luciano Coelho94210892009-12-11 15:40:55 +0200366 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300367 if (ret < 0)
368 return ret;
369
370 return 0;
371}
372
373static void wl1271_disable_interrupts(struct wl1271 *wl)
374{
375 disable_irq(wl->irq);
376}
377
378static void wl1271_power_off(struct wl1271 *wl)
379{
380 wl->set_power(false);
Luciano Coelho98b2a682009-12-11 15:40:52 +0200381 wl->gpio_power = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382}
383
384static void wl1271_power_on(struct wl1271 *wl)
385{
386 wl->set_power(true);
Luciano Coelho98b2a682009-12-11 15:40:52 +0200387 wl->gpio_power = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300388}
389
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300390static void wl1271_fw_status(struct wl1271 *wl,
391 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300392{
393 u32 total = 0;
394 int i;
395
Juuso Oikarinen74621412009-10-12 15:08:54 +0300396 wl1271_spi_read(wl, FW_STATUS_ADDR, status,
397 sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300398
399 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
400 "drv_rx_counter = %d, tx_results_counter = %d)",
401 status->intr,
402 status->fw_rx_counter,
403 status->drv_rx_counter,
404 status->tx_results_counter);
405
406 /* update number of available TX blocks */
407 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300408 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
409 wl->tx_blocks_freed[i];
410
411 wl->tx_blocks_freed[i] =
412 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300413 wl->tx_blocks_available += cnt;
414 total += cnt;
415 }
416
417 /* if more blocks are available now, schedule some tx work */
418 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300419 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420
421 /* update the host-chipset time offset */
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300422 wl->time_offset = jiffies_to_usecs(jiffies) -
423 le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424}
425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300426static void wl1271_irq_work(struct work_struct *work)
427{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300428 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300429 u32 intr;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430 struct wl1271 *wl =
431 container_of(work, struct wl1271, irq_work);
432
433 mutex_lock(&wl->mutex);
434
435 wl1271_debug(DEBUG_IRQ, "IRQ work");
436
437 if (wl->state == WL1271_STATE_OFF)
438 goto out;
439
440 ret = wl1271_ps_elp_wakeup(wl, true);
441 if (ret < 0)
442 goto out;
443
Juuso Oikarinen74621412009-10-12 15:08:54 +0300444 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300446 wl1271_fw_status(wl, wl->fw_status);
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300447 intr = le32_to_cpu(wl->fw_status->intr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300448 if (!intr) {
449 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
450 goto out_sleep;
451 }
452
453 intr &= WL1271_INTR_MASK;
454
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300455 if (intr & WL1271_ACX_INTR_EVENT_A) {
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300456 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200457 wl1271_event_handle(wl, 0);
Juuso Oikarinen1fd27942009-10-13 12:47:54 +0300458 }
459
460 if (intr & WL1271_ACX_INTR_EVENT_B) {
461 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200462 wl1271_event_handle(wl, 1);
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300463 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300465 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
466 wl1271_debug(DEBUG_IRQ,
467 "WL1271_ACX_INTR_INIT_COMPLETE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300469 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
470 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300471
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300472 if (intr & WL1271_ACX_INTR_DATA) {
473 u8 tx_res_cnt = wl->fw_status->tx_results_counter -
474 wl->tx_results_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300475
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300476 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300477
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300478 /* check for tx results */
479 if (tx_res_cnt)
480 wl1271_tx_complete(wl, tx_res_cnt);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300482 wl1271_rx(wl, wl->fw_status);
483 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484
485out_sleep:
Juuso Oikarinen74621412009-10-12 15:08:54 +0300486 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
Luciano Coelho73d0a132009-08-11 11:58:27 +0300487 WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300488 wl1271_ps_elp_sleep(wl);
489
490out:
491 mutex_unlock(&wl->mutex);
492}
493
494static irqreturn_t wl1271_irq(int irq, void *cookie)
495{
496 struct wl1271 *wl;
497 unsigned long flags;
498
499 wl1271_debug(DEBUG_IRQ, "IRQ");
500
501 wl = cookie;
502
503 /* complete the ELP completion */
504 spin_lock_irqsave(&wl->wl_lock, flags);
505 if (wl->elp_compl) {
506 complete(wl->elp_compl);
507 wl->elp_compl = NULL;
508 }
509
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300510 ieee80211_queue_work(wl->hw, &wl->irq_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511 spin_unlock_irqrestore(&wl->wl_lock, flags);
512
513 return IRQ_HANDLED;
514}
515
516static int wl1271_fetch_firmware(struct wl1271 *wl)
517{
518 const struct firmware *fw;
519 int ret;
520
521 ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
522
523 if (ret < 0) {
524 wl1271_error("could not get firmware: %d", ret);
525 return ret;
526 }
527
528 if (fw->size % 4) {
529 wl1271_error("firmware size is not multiple of 32 bits: %zu",
530 fw->size);
531 ret = -EILSEQ;
532 goto out;
533 }
534
535 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300536 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300537
538 if (!wl->fw) {
539 wl1271_error("could not allocate memory for the firmware");
540 ret = -ENOMEM;
541 goto out;
542 }
543
544 memcpy(wl->fw, fw->data, wl->fw_len);
545
546 ret = 0;
547
548out:
549 release_firmware(fw);
550
551 return ret;
552}
553
554static int wl1271_fetch_nvs(struct wl1271 *wl)
555{
556 const struct firmware *fw;
557 int ret;
558
559 ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
560
561 if (ret < 0) {
562 wl1271_error("could not get nvs file: %d", ret);
563 return ret;
564 }
565
566 if (fw->size % 4) {
567 wl1271_error("nvs size is not multiple of 32 bits: %zu",
568 fw->size);
569 ret = -EILSEQ;
570 goto out;
571 }
572
573 wl->nvs_len = fw->size;
574 wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
575
576 if (!wl->nvs) {
577 wl1271_error("could not allocate memory for the nvs file");
578 ret = -ENOMEM;
579 goto out;
580 }
581
582 memcpy(wl->nvs, fw->data, wl->nvs_len);
583
584 ret = 0;
585
586out:
587 release_firmware(fw);
588
589 return ret;
590}
591
592static void wl1271_fw_wakeup(struct wl1271 *wl)
593{
594 u32 elp_reg;
595
596 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300597 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300598}
599
600static int wl1271_setup(struct wl1271 *wl)
601{
602 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
603 if (!wl->fw_status)
604 return -ENOMEM;
605
606 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
607 if (!wl->tx_res_if) {
608 kfree(wl->fw_status);
609 return -ENOMEM;
610 }
611
612 INIT_WORK(&wl->irq_work, wl1271_irq_work);
613 INIT_WORK(&wl->tx_work, wl1271_tx_work);
614 return 0;
615}
616
617static int wl1271_chip_wakeup(struct wl1271 *wl)
618{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300619 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300620 int ret = 0;
621
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200622 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300623 wl1271_power_on(wl);
624 msleep(WL1271_POWER_ON_SLEEP);
625 wl1271_spi_reset(wl);
626 wl1271_spi_init(wl);
627
628 /* We don't need a real memory partition here, because we only want
629 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300630 memset(&partition, 0, sizeof(partition));
631 partition.reg.start = REGISTERS_BASE;
632 partition.reg.size = REGISTERS_DOWN_SIZE;
633 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634
635 /* ELP module wake up */
636 wl1271_fw_wakeup(wl);
637
638 /* whal_FwCtrl_BootSm() */
639
640 /* 0. read chip id from CHIP_ID */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300641 wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642
643 /* 1. check if chip id is valid */
644
645 switch (wl->chip.id) {
646 case CHIP_ID_1271_PG10:
647 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
648 wl->chip.id);
649
650 ret = wl1271_setup(wl);
651 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200652 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300653 break;
654 case CHIP_ID_1271_PG20:
655 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
656 wl->chip.id);
657
658 ret = wl1271_setup(wl);
659 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200660 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661 break;
662 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200665 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300666 }
667
668 if (wl->fw == NULL) {
669 ret = wl1271_fetch_firmware(wl);
670 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200671 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 }
673
674 /* No NVS from netlink, try to get it from the filesystem */
675 if (wl->nvs == NULL) {
676 ret = wl1271_fetch_nvs(wl);
677 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200678 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 }
680
681out:
682 return ret;
683}
684
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685int wl1271_plt_start(struct wl1271 *wl)
686{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200687 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 int ret;
689
690 mutex_lock(&wl->mutex);
691
692 wl1271_notice("power up");
693
694 if (wl->state != WL1271_STATE_OFF) {
695 wl1271_error("cannot go into PLT state because not "
696 "in off state: %d", wl->state);
697 ret = -EBUSY;
698 goto out;
699 }
700
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200701 while (retries) {
702 retries--;
703 ret = wl1271_chip_wakeup(wl);
704 if (ret < 0)
705 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200707 ret = wl1271_boot(wl);
708 if (ret < 0)
709 goto power_off;
710
711 ret = wl1271_plt_init(wl);
712 if (ret < 0)
713 goto irq_disable;
714
715 /* Make sure power saving is disabled */
716 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
717 if (ret < 0)
718 goto irq_disable;
719
720 wl->state = WL1271_STATE_PLT;
721 wl1271_notice("firmware booted in PLT mode (%s)",
722 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723 goto out;
724
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200725irq_disable:
726 wl1271_disable_interrupts(wl);
727 mutex_unlock(&wl->mutex);
728 /* Unlocking the mutex in the middle of handling is
729 inherently unsafe. In this case we deem it safe to do,
730 because we need to let any possibly pending IRQ out of
731 the system (and while we are WL1271_STATE_OFF the IRQ
732 work function will not do anything.) Also, any other
733 possible concurrent operations will fail due to the
734 current state, hence the wl1271 struct should be safe. */
735 cancel_work_sync(&wl->irq_work);
736 mutex_lock(&wl->mutex);
737power_off:
738 wl1271_power_off(wl);
739 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200741 wl1271_error("firmware boot in PLT mode failed despite %d retries",
742 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300743out:
744 mutex_unlock(&wl->mutex);
745
746 return ret;
747}
748
749int wl1271_plt_stop(struct wl1271 *wl)
750{
751 int ret = 0;
752
753 mutex_lock(&wl->mutex);
754
755 wl1271_notice("power down");
756
757 if (wl->state != WL1271_STATE_PLT) {
758 wl1271_error("cannot power down because not in PLT "
759 "state: %d", wl->state);
760 ret = -EBUSY;
761 goto out;
762 }
763
764 wl1271_disable_interrupts(wl);
765 wl1271_power_off(wl);
766
767 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300768 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769
770out:
771 mutex_unlock(&wl->mutex);
772
773 return ret;
774}
775
776
777static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
778{
779 struct wl1271 *wl = hw->priv;
780
781 skb_queue_tail(&wl->tx_queue, skb);
782
783 /*
784 * The chip specific setup must run before the first TX packet -
785 * before that, the tx_work will not be initialized!
786 */
787
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300788 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789
790 /*
791 * The workqueue is slow to process the tx_queue and we need stop
792 * the queue here, otherwise the queue will get too long.
793 */
794 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
795 ieee80211_stop_queues(wl->hw);
796
797 /*
798 * FIXME: this is racy, the variable is not properly
799 * protected. Maybe fix this by removing the stupid
800 * variable altogether and checking the real queue state?
801 */
802 wl->tx_queue_stopped = true;
803 }
804
805 return NETDEV_TX_OK;
806}
807
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300808static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
809 void *arg)
810{
811 struct net_device *dev;
812 struct wireless_dev *wdev;
813 struct wiphy *wiphy;
814 struct ieee80211_hw *hw;
815 struct wl1271 *wl;
816 struct wl1271 *wl_temp;
817 struct in_device *idev;
818 struct in_ifaddr *ifa = arg;
819 int ret = 0;
820
821 /* FIXME: this ugly function should probably be implemented in the
822 * mac80211, and here should only be a simple callback handling actual
823 * setting of the filters. Now we need to dig up references to
824 * various structures to gain access to what we need.
825 * Also, because of this, there is no "initial" setting of the filter
826 * in "op_start", because we don't want to dig up struct net_device
827 * there - the filter will be set upon first change of the interface
828 * IP address. */
829
830 dev = ifa->ifa_dev->dev;
831
832 wdev = dev->ieee80211_ptr;
833 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200834 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300835
836 wiphy = wdev->wiphy;
837 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200838 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300839
840 hw = wiphy_priv(wiphy);
841 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200842 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300843
844 /* Check that the interface is one supported by this driver. */
845 wl_temp = hw->priv;
846 list_for_each_entry(wl, &wl_list, list) {
847 if (wl == wl_temp)
848 break;
849 }
850 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200851 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300852
853 /* Get the interface IP address for the device. "ifa" will become
854 NULL if:
855 - there is no IPV4 protocol address configured
856 - there are multiple (virtual) IPV4 addresses configured
857 When "ifa" is NULL, filtering will be disabled.
858 */
859 ifa = NULL;
860 idev = dev->ip_ptr;
861 if (idev)
862 ifa = idev->ifa_list;
863
864 if (ifa && ifa->ifa_next)
865 ifa = NULL;
866
867 mutex_lock(&wl->mutex);
868
869 if (wl->state == WL1271_STATE_OFF)
870 goto out;
871
872 ret = wl1271_ps_elp_wakeup(wl, false);
873 if (ret < 0)
874 goto out;
875 if (ifa)
876 ret = wl1271_acx_arp_ip_filter(wl, true,
877 (u8 *)&ifa->ifa_address,
878 ACX_IPV4_VERSION);
879 else
880 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
881 ACX_IPV4_VERSION);
882 wl1271_ps_elp_sleep(wl);
883
884out:
885 mutex_unlock(&wl->mutex);
886
Luciano Coelho17d72652009-11-23 23:22:15 +0200887 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300888}
889
890static struct notifier_block wl1271_dev_notifier = {
891 .notifier_call = wl1271_dev_notify,
892};
893
894
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895static int wl1271_op_start(struct ieee80211_hw *hw)
896{
897 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200898 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 int ret = 0;
900
901 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
902
903 mutex_lock(&wl->mutex);
904
905 if (wl->state != WL1271_STATE_OFF) {
906 wl1271_error("cannot start because not in off state: %d",
907 wl->state);
908 ret = -EBUSY;
909 goto out;
910 }
911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 while (retries) {
913 retries--;
914 ret = wl1271_chip_wakeup(wl);
915 if (ret < 0)
916 goto power_off;
917
918 ret = wl1271_boot(wl);
919 if (ret < 0)
920 goto power_off;
921
922 ret = wl1271_hw_init(wl);
923 if (ret < 0)
924 goto irq_disable;
925
926 wl->state = WL1271_STATE_ON;
927 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928 goto out;
929
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200930irq_disable:
931 wl1271_disable_interrupts(wl);
932 mutex_unlock(&wl->mutex);
933 /* Unlocking the mutex in the middle of handling is
934 inherently unsafe. In this case we deem it safe to do,
935 because we need to let any possibly pending IRQ out of
936 the system (and while we are WL1271_STATE_OFF the IRQ
937 work function will not do anything.) Also, any other
938 possible concurrent operations will fail due to the
939 current state, hence the wl1271 struct should be safe. */
940 cancel_work_sync(&wl->irq_work);
941 mutex_lock(&wl->mutex);
942power_off:
943 wl1271_power_off(wl);
944 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200946 wl1271_error("firmware boot failed despite %d retries",
947 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300948out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 mutex_unlock(&wl->mutex);
950
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300951 if (!ret) {
952 list_add(&wl->list, &wl_list);
953 register_inetaddr_notifier(&wl1271_dev_notifier);
954 }
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 return ret;
957}
958
959static void wl1271_op_stop(struct ieee80211_hw *hw)
960{
961 struct wl1271 *wl = hw->priv;
962 int i;
963
964 wl1271_info("down");
965
966 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
967
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300968 unregister_inetaddr_notifier(&wl1271_dev_notifier);
969 list_del(&wl->list);
970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 mutex_lock(&wl->mutex);
972
973 WARN_ON(wl->state != WL1271_STATE_ON);
974
975 if (wl->scanning) {
976 mutex_unlock(&wl->mutex);
977 ieee80211_scan_completed(wl->hw, true);
978 mutex_lock(&wl->mutex);
979 wl->scanning = false;
980 }
981
982 wl->state = WL1271_STATE_OFF;
983
984 wl1271_disable_interrupts(wl);
985
986 mutex_unlock(&wl->mutex);
987
988 cancel_work_sync(&wl->irq_work);
989 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990
991 mutex_lock(&wl->mutex);
992
993 /* let's notify MAC80211 about the remaining pending TX frames */
994 wl1271_tx_flush(wl);
995 wl1271_power_off(wl);
996
997 memset(wl->bssid, 0, ETH_ALEN);
998 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
999 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001001 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 wl->rx_counter = 0;
1004 wl->elp = false;
1005 wl->psm = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001006 wl->psm_entry_retry = 0;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001007 wl->associated = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008 wl->tx_queue_stopped = false;
1009 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1010 wl->tx_blocks_available = 0;
1011 wl->tx_results_count = 0;
1012 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001013 wl->tx_security_last_seq = 0;
1014 wl->tx_security_seq_16 = 0;
1015 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->time_offset = 0;
1017 wl->session_counter = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001018 wl->joined = false;
1019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020 for (i = 0; i < NUM_TX_QUEUES; i++)
1021 wl->tx_blocks_freed[i] = 0;
1022
1023 wl1271_debugfs_reset(wl);
1024 mutex_unlock(&wl->mutex);
1025}
1026
1027static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1028 struct ieee80211_if_init_conf *conf)
1029{
1030 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 int ret = 0;
1032
John W. Linvillee5539bc2009-08-18 10:50:34 -04001033 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1034 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
1036 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001037 if (wl->vif) {
1038 ret = -EBUSY;
1039 goto out;
1040 }
1041
1042 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
1044 switch (conf->type) {
1045 case NL80211_IFTYPE_STATION:
1046 wl->bss_type = BSS_TYPE_STA_BSS;
1047 break;
1048 case NL80211_IFTYPE_ADHOC:
1049 wl->bss_type = BSS_TYPE_IBSS;
1050 break;
1051 default:
1052 ret = -EOPNOTSUPP;
1053 goto out;
1054 }
1055
1056 /* FIXME: what if conf->mac_addr changes? */
1057
1058out:
1059 mutex_unlock(&wl->mutex);
1060 return ret;
1061}
1062
1063static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1064 struct ieee80211_if_init_conf *conf)
1065{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001066 struct wl1271 *wl = hw->priv;
1067
1068 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001070 wl->vif = NULL;
1071 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072}
1073
1074#if 0
1075static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1076 struct ieee80211_vif *vif,
1077 struct ieee80211_if_conf *conf)
1078{
1079 struct wl1271 *wl = hw->priv;
1080 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 int ret;
1082
David S. Miller32646902009-09-17 10:18:30 -07001083 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1084 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1086 conf->ssid_len);
1087
1088 mutex_lock(&wl->mutex);
1089
1090 ret = wl1271_ps_elp_wakeup(wl, false);
1091 if (ret < 0)
1092 goto out;
1093
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001094 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1095 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1096
1097 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1098
1099 ret = wl1271_cmd_join(wl);
1100 if (ret < 0)
1101 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001102
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001103 ret = wl1271_cmd_build_null_data(wl);
1104 if (ret < 0)
1105 goto out_sleep;
1106 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107
1108 wl->ssid_len = conf->ssid_len;
1109 if (wl->ssid_len)
1110 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1111
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112 if (conf->changed & IEEE80211_IFCC_BEACON) {
1113 beacon = ieee80211_beacon_get(hw, vif);
1114 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1115 beacon->data, beacon->len);
1116
1117 if (ret < 0) {
1118 dev_kfree_skb(beacon);
1119 goto out_sleep;
1120 }
1121
1122 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1123 beacon->data, beacon->len);
1124
1125 dev_kfree_skb(beacon);
1126
1127 if (ret < 0)
1128 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129 }
1130
1131out_sleep:
1132 wl1271_ps_elp_sleep(wl);
1133
1134out:
1135 mutex_unlock(&wl->mutex);
1136
1137 return ret;
1138}
1139#endif
1140
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001141static int wl1271_join_channel(struct wl1271 *wl, int channel)
1142{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001143 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001144 /* we need to use a dummy BSSID for now */
1145 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1146 0xad, 0xbe, 0xef };
1147
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001148 /* the dummy join is not required for ad-hoc */
1149 if (wl->bss_type == BSS_TYPE_IBSS)
1150 goto out;
1151
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001152 /* disable mac filter, so we hear everything */
1153 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1154
1155 wl->channel = channel;
1156 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1157
1158 ret = wl1271_cmd_join(wl);
1159 if (ret < 0)
1160 goto out;
1161
1162 wl->joined = true;
1163
1164out:
1165 return ret;
1166}
1167
1168static int wl1271_unjoin_channel(struct wl1271 *wl)
1169{
1170 int ret;
1171
1172 /* to stop listening to a channel, we disconnect */
1173 ret = wl1271_cmd_disconnect(wl);
1174 if (ret < 0)
1175 goto out;
1176
1177 wl->joined = false;
1178 wl->channel = 0;
1179 memset(wl->bssid, 0, ETH_ALEN);
1180 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1181
1182out:
1183 return ret;
1184}
1185
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1187{
1188 struct wl1271 *wl = hw->priv;
1189 struct ieee80211_conf *conf = &hw->conf;
1190 int channel, ret = 0;
1191
1192 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1193
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001194 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195 channel,
1196 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001197 conf->power_level,
1198 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001199
1200 mutex_lock(&wl->mutex);
1201
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001202 wl->band = conf->channel->band;
1203
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 ret = wl1271_ps_elp_wakeup(wl, false);
1205 if (ret < 0)
1206 goto out;
1207
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1209 if (conf->flags & IEEE80211_CONF_IDLE && wl->joined)
1210 wl1271_unjoin_channel(wl);
1211 else
1212 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001213
1214 if (conf->flags & IEEE80211_CONF_IDLE) {
1215 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
1216 wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC);
1217 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 }
1219
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001220 /* if the channel changes while joined, join again */
1221 if (channel != wl->channel && wl->joined)
1222 wl1271_join_channel(wl, channel);
1223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224 if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225 wl->psm_requested = true;
1226
1227 /*
1228 * We enter PSM only if we're already associated.
1229 * If we're not, we'll enter it when joining an SSID,
1230 * through the bss_info_changed() hook.
1231 */
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001232 if (wl->associated) {
1233 wl1271_info("psm enabled");
1234 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1235 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
1237 wl->psm_requested) {
1238 wl1271_info("psm disabled");
1239
1240 wl->psm_requested = false;
1241
1242 if (wl->psm)
1243 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1244 }
1245
1246 if (conf->power_level != wl->power_level) {
1247 ret = wl1271_acx_tx_power(wl, conf->power_level);
1248 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001249 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250
1251 wl->power_level = conf->power_level;
1252 }
1253
1254out_sleep:
1255 wl1271_ps_elp_sleep(wl);
1256
1257out:
1258 mutex_unlock(&wl->mutex);
1259
1260 return ret;
1261}
1262
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001263struct wl1271_filter_params {
1264 bool enabled;
1265 int mc_list_length;
1266 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1267};
1268
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001269static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1270 struct dev_addr_list *mc_list)
1271{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001272 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001273 int i;
1274
Juuso Oikarinen74441132009-10-13 12:47:53 +03001275 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001276 if (!fp) {
1277 wl1271_error("Out of memory setting filters.");
1278 return 0;
1279 }
1280
1281 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001282 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001283 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1284 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001285 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001286 }
1287
1288 fp->mc_list_length = 0;
1289 for (i = 0; i < mc_count; i++) {
1290 if (mc_list->da_addrlen == ETH_ALEN) {
1291 memcpy(fp->mc_list[fp->mc_list_length],
1292 mc_list->da_addr, ETH_ALEN);
1293 fp->mc_list_length++;
1294 } else
1295 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001296 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001297 }
1298
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001299 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001300}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001302#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1303 FIF_ALLMULTI | \
1304 FIF_FCSFAIL | \
1305 FIF_BCN_PRBRESP_PROMISC | \
1306 FIF_CONTROL | \
1307 FIF_OTHER_BSS)
1308
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1310 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001311 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001313 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001315 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
1317 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1318
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001319 mutex_lock(&wl->mutex);
1320
1321 if (wl->state == WL1271_STATE_OFF)
1322 goto out;
1323
1324 ret = wl1271_ps_elp_wakeup(wl, false);
1325 if (ret < 0)
1326 goto out;
1327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328 *total &= WL1271_SUPPORTED_FILTERS;
1329 changed &= WL1271_SUPPORTED_FILTERS;
1330
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001331 if (*total & FIF_ALLMULTI)
1332 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1333 else if (fp)
1334 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1335 fp->mc_list,
1336 fp->mc_list_length);
1337 if (ret < 0)
1338 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001340 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001341
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001342 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 /* determine, whether supported filter values have changed */
1345 if (changed == 0)
1346 goto out_sleep;
1347
1348 /* apply configured filters */
1349 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1350 if (ret < 0)
1351 goto out_sleep;
1352
1353out_sleep:
1354 wl1271_ps_elp_sleep(wl);
1355
1356out:
1357 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358}
1359
1360static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1361 struct ieee80211_vif *vif,
1362 struct ieee80211_sta *sta,
1363 struct ieee80211_key_conf *key_conf)
1364{
1365 struct wl1271 *wl = hw->priv;
1366 const u8 *addr;
1367 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001368 u32 tx_seq_32 = 0;
1369 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 u8 key_type;
1371
1372 static const u8 bcast_addr[ETH_ALEN] =
1373 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1374
1375 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1376
1377 addr = sta ? sta->addr : bcast_addr;
1378
1379 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1380 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1381 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1382 key_conf->alg, key_conf->keyidx,
1383 key_conf->keylen, key_conf->flags);
1384 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1385
1386 if (is_zero_ether_addr(addr)) {
1387 /* We dont support TX only encryption */
1388 ret = -EOPNOTSUPP;
1389 goto out;
1390 }
1391
1392 mutex_lock(&wl->mutex);
1393
1394 ret = wl1271_ps_elp_wakeup(wl, false);
1395 if (ret < 0)
1396 goto out_unlock;
1397
1398 switch (key_conf->alg) {
1399 case ALG_WEP:
1400 key_type = KEY_WEP;
1401
1402 key_conf->hw_key_idx = key_conf->keyidx;
1403 break;
1404 case ALG_TKIP:
1405 key_type = KEY_TKIP;
1406
1407 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001408 tx_seq_32 = wl->tx_security_seq_32;
1409 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410 break;
1411 case ALG_CCMP:
1412 key_type = KEY_AES;
1413
1414 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001415 tx_seq_32 = wl->tx_security_seq_32;
1416 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 break;
1418 default:
1419 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1420
1421 ret = -EOPNOTSUPP;
1422 goto out_sleep;
1423 }
1424
1425 switch (cmd) {
1426 case SET_KEY:
1427 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1428 key_conf->keyidx, key_type,
1429 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001430 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431 if (ret < 0) {
1432 wl1271_error("Could not add or replace key");
1433 goto out_sleep;
1434 }
1435 break;
1436
1437 case DISABLE_KEY:
1438 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1439 key_conf->keyidx, key_type,
1440 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001441 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442 if (ret < 0) {
1443 wl1271_error("Could not remove key");
1444 goto out_sleep;
1445 }
1446 break;
1447
1448 default:
1449 wl1271_error("Unsupported key cmd 0x%x", cmd);
1450 ret = -EOPNOTSUPP;
1451 goto out_sleep;
1452
1453 break;
1454 }
1455
1456out_sleep:
1457 wl1271_ps_elp_sleep(wl);
1458
1459out_unlock:
1460 mutex_unlock(&wl->mutex);
1461
1462out:
1463 return ret;
1464}
1465
1466static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1467 struct cfg80211_scan_request *req)
1468{
1469 struct wl1271 *wl = hw->priv;
1470 int ret;
1471 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001472 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473
1474 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1475
1476 if (req->n_ssids) {
1477 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001478 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 }
1480
1481 mutex_lock(&wl->mutex);
1482
1483 ret = wl1271_ps_elp_wakeup(wl, false);
1484 if (ret < 0)
1485 goto out;
1486
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001487 if (wl1271_11a_enabled())
1488 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1489 WL1271_SCAN_BAND_DUAL, 3);
1490 else
1491 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1492 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493
1494 wl1271_ps_elp_sleep(wl);
1495
1496out:
1497 mutex_unlock(&wl->mutex);
1498
1499 return ret;
1500}
1501
1502static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1503{
1504 struct wl1271 *wl = hw->priv;
1505 int ret;
1506
1507 mutex_lock(&wl->mutex);
1508
1509 ret = wl1271_ps_elp_wakeup(wl, false);
1510 if (ret < 0)
1511 goto out;
1512
1513 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1514 if (ret < 0)
1515 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1516
1517 wl1271_ps_elp_sleep(wl);
1518
1519out:
1520 mutex_unlock(&wl->mutex);
1521
1522 return ret;
1523}
1524
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001525static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
1526{
1527 struct ieee80211_supported_band *band;
1528 u32 enabled_rates = 0;
1529 int bit;
1530
1531 band = wl->hw->wiphy->bands[wl->band];
1532 for (bit = 0; bit < band->n_bitrates; bit++) {
1533 if (basic_rate_set & 0x1)
1534 enabled_rates |= band->bitrates[bit].hw_value;
1535 basic_rate_set >>= 1;
1536 }
1537
1538 return enabled_rates;
1539}
1540
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001541static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1542 struct ieee80211_vif *vif,
1543 struct ieee80211_bss_conf *bss_conf,
1544 u32 changed)
1545{
1546 enum wl1271_cmd_ps_mode mode;
1547 struct wl1271 *wl = hw->priv;
1548 int ret;
1549
1550 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1551
1552 mutex_lock(&wl->mutex);
1553
1554 ret = wl1271_ps_elp_wakeup(wl, false);
1555 if (ret < 0)
1556 goto out;
1557
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001558 if ((changed & BSS_CHANGED_BSSID) &&
1559 /*
1560 * Now we know the correct bssid, so we send a new join command
1561 * and enable the BSSID filter
1562 */
1563 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1564 wl->rx_config |= CFG_BSSID_FILTER_EN;
1565 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Luciano Coelhobdcbbb92009-12-11 15:40:48 +02001566 ret = wl1271_cmd_build_null_data(wl);
1567 if (ret < 0) {
1568 wl1271_warning("cmd buld null data failed %d",
1569 ret);
1570 goto out_sleep;
1571 }
Luciano Coelhocd264762009-12-11 15:40:47 +02001572 ret = wl1271_cmd_join(wl);
1573 if (ret < 0) {
1574 wl1271_warning("cmd join failed %d", ret);
1575 goto out_sleep;
1576 }
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001577 wl->joined = true;
1578 }
1579
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001580 if (wl->bss_type == BSS_TYPE_IBSS) {
1581 /* FIXME: This implements rudimentary ad-hoc support -
1582 proper templates are on the wish list and notification
1583 on when they change. This patch will update the templates
1584 on every call to this function. Also, the firmware will not
1585 answer to probe-requests as it does not have the proper
1586 SSID set in the JOIN command. The probe-response template
1587 is set nevertheless, as the FW will ASSERT without it */
1588 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1589
1590 if (beacon) {
1591 struct ieee80211_hdr *hdr;
1592 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1593 beacon->data,
1594 beacon->len);
1595
1596 if (ret < 0) {
1597 dev_kfree_skb(beacon);
1598 goto out_sleep;
1599 }
1600
1601 hdr = (struct ieee80211_hdr *) beacon->data;
1602 hdr->frame_control = cpu_to_le16(
1603 IEEE80211_FTYPE_MGMT |
1604 IEEE80211_STYPE_PROBE_RESP);
1605
1606 ret = wl1271_cmd_template_set(wl,
1607 CMD_TEMPL_PROBE_RESPONSE,
1608 beacon->data,
1609 beacon->len);
1610 dev_kfree_skb(beacon);
1611 if (ret < 0)
1612 goto out_sleep;
1613 }
1614 }
1615
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001616 if (changed & BSS_CHANGED_ASSOC) {
1617 if (bss_conf->assoc) {
1618 wl->aid = bss_conf->aid;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001619 wl->associated = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001621 /*
1622 * with wl1271, we don't need to update the
1623 * beacon_int and dtim_period, because the firmware
1624 * updates it by itself when the first beacon is
1625 * received after a join.
1626 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001627 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1628 if (ret < 0)
1629 goto out_sleep;
1630
1631 ret = wl1271_acx_aid(wl, wl->aid);
1632 if (ret < 0)
1633 goto out_sleep;
1634
1635 /* If we want to go in PSM but we're not there yet */
1636 if (wl->psm_requested && !wl->psm) {
1637 mode = STATION_POWER_SAVE_MODE;
1638 ret = wl1271_ps_set_mode(wl, mode);
1639 if (ret < 0)
1640 goto out_sleep;
1641 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001642 } else {
1643 /* use defaults when not associated */
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001644 wl->associated = false;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001645 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001646 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 if (changed & BSS_CHANGED_ERP_SLOT) {
1651 if (bss_conf->use_short_slot)
1652 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1653 else
1654 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1655 if (ret < 0) {
1656 wl1271_warning("Set slot time failed %d", ret);
1657 goto out_sleep;
1658 }
1659 }
1660
1661 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1662 if (bss_conf->use_short_preamble)
1663 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1664 else
1665 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1666 }
1667
1668 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1669 if (bss_conf->use_cts_prot)
1670 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1671 else
1672 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1673 if (ret < 0) {
1674 wl1271_warning("Set ctsprotect failed %d", ret);
1675 goto out_sleep;
1676 }
1677 }
1678
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001679 if (changed & BSS_CHANGED_BASIC_RATES) {
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001680 wl->basic_rate_set = wl1271_enabled_rates_get(
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001681 wl, bss_conf->basic_rates);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001682
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001683 ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001684 if (ret < 0) {
1685 wl1271_warning("Set rate policies failed %d", ret);
1686 goto out_sleep;
1687 }
1688 }
1689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690out_sleep:
1691 wl1271_ps_elp_sleep(wl);
1692
1693out:
1694 mutex_unlock(&wl->mutex);
1695}
1696
1697
1698/* can't be const, mac80211 writes to this */
1699static struct ieee80211_rate wl1271_rates[] = {
1700 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001701 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1702 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001703 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001704 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1705 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001706 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1707 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001708 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1709 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001710 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1711 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001712 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1713 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1715 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001716 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1717 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001718 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001719 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1720 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001721 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001722 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1723 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001725 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1726 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001728 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1729 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001730 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001731 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1732 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001733 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001734 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1735 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001736 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001737 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1738 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739};
1740
1741/* can't be const, mac80211 writes to this */
1742static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001743 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1744 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1745 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1746 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1747 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1748 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1749 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1750 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1751 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1752 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1753 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1754 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1755 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756};
1757
1758/* can't be const, mac80211 writes to this */
1759static struct ieee80211_supported_band wl1271_band_2ghz = {
1760 .channels = wl1271_channels,
1761 .n_channels = ARRAY_SIZE(wl1271_channels),
1762 .bitrates = wl1271_rates,
1763 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1764};
1765
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001766/* 5 GHz data rates for WL1273 */
1767static struct ieee80211_rate wl1271_rates_5ghz[] = {
1768 { .bitrate = 60,
1769 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1770 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1771 { .bitrate = 90,
1772 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1773 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1774 { .bitrate = 120,
1775 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1776 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1777 { .bitrate = 180,
1778 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1779 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1780 { .bitrate = 240,
1781 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1782 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1783 { .bitrate = 360,
1784 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1785 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1786 { .bitrate = 480,
1787 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1788 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1789 { .bitrate = 540,
1790 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1791 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1792};
1793
1794/* 5 GHz band channels for WL1273 */
1795static struct ieee80211_channel wl1271_channels_5ghz[] = {
1796 { .hw_value = 183, .center_freq = 4915},
1797 { .hw_value = 184, .center_freq = 4920},
1798 { .hw_value = 185, .center_freq = 4925},
1799 { .hw_value = 187, .center_freq = 4935},
1800 { .hw_value = 188, .center_freq = 4940},
1801 { .hw_value = 189, .center_freq = 4945},
1802 { .hw_value = 192, .center_freq = 4960},
1803 { .hw_value = 196, .center_freq = 4980},
1804 { .hw_value = 7, .center_freq = 5035},
1805 { .hw_value = 8, .center_freq = 5040},
1806 { .hw_value = 9, .center_freq = 5045},
1807 { .hw_value = 11, .center_freq = 5055},
1808 { .hw_value = 12, .center_freq = 5060},
1809 { .hw_value = 16, .center_freq = 5080},
1810 { .hw_value = 34, .center_freq = 5170},
1811 { .hw_value = 36, .center_freq = 5180},
1812 { .hw_value = 38, .center_freq = 5190},
1813 { .hw_value = 40, .center_freq = 5200},
1814 { .hw_value = 42, .center_freq = 5210},
1815 { .hw_value = 44, .center_freq = 5220},
1816 { .hw_value = 46, .center_freq = 5230},
1817 { .hw_value = 48, .center_freq = 5240},
1818 { .hw_value = 52, .center_freq = 5260},
1819 { .hw_value = 56, .center_freq = 5280},
1820 { .hw_value = 60, .center_freq = 5300},
1821 { .hw_value = 64, .center_freq = 5320},
1822 { .hw_value = 100, .center_freq = 5500},
1823 { .hw_value = 104, .center_freq = 5520},
1824 { .hw_value = 108, .center_freq = 5540},
1825 { .hw_value = 112, .center_freq = 5560},
1826 { .hw_value = 116, .center_freq = 5580},
1827 { .hw_value = 120, .center_freq = 5600},
1828 { .hw_value = 124, .center_freq = 5620},
1829 { .hw_value = 128, .center_freq = 5640},
1830 { .hw_value = 132, .center_freq = 5660},
1831 { .hw_value = 136, .center_freq = 5680},
1832 { .hw_value = 140, .center_freq = 5700},
1833 { .hw_value = 149, .center_freq = 5745},
1834 { .hw_value = 153, .center_freq = 5765},
1835 { .hw_value = 157, .center_freq = 5785},
1836 { .hw_value = 161, .center_freq = 5805},
1837 { .hw_value = 165, .center_freq = 5825},
1838};
1839
1840
1841static struct ieee80211_supported_band wl1271_band_5ghz = {
1842 .channels = wl1271_channels_5ghz,
1843 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1844 .bitrates = wl1271_rates_5ghz,
1845 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1846};
1847
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001848static const struct ieee80211_ops wl1271_ops = {
1849 .start = wl1271_op_start,
1850 .stop = wl1271_op_stop,
1851 .add_interface = wl1271_op_add_interface,
1852 .remove_interface = wl1271_op_remove_interface,
1853 .config = wl1271_op_config,
1854/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001855 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856 .configure_filter = wl1271_op_configure_filter,
1857 .tx = wl1271_op_tx,
1858 .set_key = wl1271_op_set_key,
1859 .hw_scan = wl1271_op_hw_scan,
1860 .bss_info_changed = wl1271_op_bss_info_changed,
1861 .set_rts_threshold = wl1271_op_set_rts_threshold,
1862};
1863
1864static int wl1271_register_hw(struct wl1271 *wl)
1865{
1866 int ret;
1867
1868 if (wl->mac80211_registered)
1869 return 0;
1870
1871 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1872
1873 ret = ieee80211_register_hw(wl->hw);
1874 if (ret < 0) {
1875 wl1271_error("unable to register mac80211 hw: %d", ret);
1876 return ret;
1877 }
1878
1879 wl->mac80211_registered = true;
1880
1881 wl1271_notice("loaded");
1882
1883 return 0;
1884}
1885
1886static int wl1271_init_ieee80211(struct wl1271 *wl)
1887{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001888 /* The tx descriptor buffer and the TKIP space. */
1889 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1890 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001891
1892 /* unit us */
1893 /* FIXME: find a proper value */
1894 wl->hw->channel_change_time = 10000;
1895
1896 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001897 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001898 IEEE80211_HW_BEACON_FILTER |
1899 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001900
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001901 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1902 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001903 wl->hw->wiphy->max_scan_ssids = 1;
1904 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1905
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001906 if (wl1271_11a_enabled())
1907 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1908
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001909 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1910
1911 return 0;
1912}
1913
1914static void wl1271_device_release(struct device *dev)
1915{
1916
1917}
1918
1919static struct platform_device wl1271_device = {
1920 .name = "wl1271",
1921 .id = -1,
1922
1923 /* device model insists to have a release function */
1924 .dev = {
1925 .release = wl1271_device_release,
1926 },
1927};
1928
1929#define WL1271_DEFAULT_CHANNEL 0
1930static int __devinit wl1271_probe(struct spi_device *spi)
1931{
1932 struct wl12xx_platform_data *pdata;
1933 struct ieee80211_hw *hw;
1934 struct wl1271 *wl;
1935 int ret, i;
1936 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1937
1938 pdata = spi->dev.platform_data;
1939 if (!pdata) {
1940 wl1271_error("no platform data");
1941 return -ENODEV;
1942 }
1943
1944 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1945 if (!hw) {
1946 wl1271_error("could not alloc ieee80211_hw");
1947 return -ENOMEM;
1948 }
1949
1950 wl = hw->priv;
1951 memset(wl, 0, sizeof(*wl));
1952
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001953 INIT_LIST_HEAD(&wl->list);
1954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 wl->hw = hw;
1956 dev_set_drvdata(&spi->dev, wl);
1957 wl->spi = spi;
1958
1959 skb_queue_head_init(&wl->tx_queue);
1960
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001961 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 wl->channel = WL1271_DEFAULT_CHANNEL;
1963 wl->scanning = false;
1964 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 wl->rx_counter = 0;
1966 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1967 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1968 wl->elp = false;
1969 wl->psm = 0;
1970 wl->psm_requested = false;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001971 wl->psm_entry_retry = 0;
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001972 wl->associated = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973 wl->tx_queue_stopped = false;
1974 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001975 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001976 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001977 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001978 wl->joined = false;
Luciano Coelho98b2a682009-12-11 15:40:52 +02001979 wl->gpio_power = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001981 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982 wl->tx_frames[i] = NULL;
1983
1984 spin_lock_init(&wl->wl_lock);
1985
1986 /*
1987 * In case our MAC address is not correctly set,
1988 * we use a random but Nokia MAC.
1989 */
1990 memcpy(wl->mac_addr, nokia_oui, 3);
1991 get_random_bytes(wl->mac_addr + 3, 3);
1992
1993 wl->state = WL1271_STATE_OFF;
1994 mutex_init(&wl->mutex);
1995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996 /* This is the only SPI value that we need to set here, the rest
1997 * comes from the board-peripherals file */
1998 spi->bits_per_word = 32;
1999
2000 ret = spi_setup(spi);
2001 if (ret < 0) {
2002 wl1271_error("spi_setup failed");
2003 goto out_free;
2004 }
2005
2006 wl->set_power = pdata->set_power;
2007 if (!wl->set_power) {
2008 wl1271_error("set power function missing in platform data");
2009 ret = -ENODEV;
2010 goto out_free;
2011 }
2012
2013 wl->irq = spi->irq;
2014 if (wl->irq < 0) {
2015 wl1271_error("irq missing in platform data");
2016 ret = -ENODEV;
2017 goto out_free;
2018 }
2019
2020 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2021 if (ret < 0) {
2022 wl1271_error("request_irq() failed: %d", ret);
2023 goto out_free;
2024 }
2025
2026 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2027
2028 disable_irq(wl->irq);
2029
2030 ret = platform_device_register(&wl1271_device);
2031 if (ret) {
2032 wl1271_error("couldn't register platform device");
2033 goto out_irq;
2034 }
2035 dev_set_drvdata(&wl1271_device.dev, wl);
2036
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002037 /* Apply default driver configuration. */
2038 wl1271_conf_init(wl);
2039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 ret = wl1271_init_ieee80211(wl);
2041 if (ret)
2042 goto out_platform;
2043
2044 ret = wl1271_register_hw(wl);
2045 if (ret)
2046 goto out_platform;
2047
2048 wl1271_debugfs_init(wl);
2049
2050 wl1271_notice("initialized");
2051
2052 return 0;
2053
2054 out_platform:
2055 platform_device_unregister(&wl1271_device);
2056
2057 out_irq:
2058 free_irq(wl->irq, wl);
2059
2060 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 ieee80211_free_hw(hw);
2062
2063 return ret;
2064}
2065
2066static int __devexit wl1271_remove(struct spi_device *spi)
2067{
2068 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2069
2070 ieee80211_unregister_hw(wl->hw);
2071
2072 wl1271_debugfs_exit(wl);
2073 platform_device_unregister(&wl1271_device);
2074 free_irq(wl->irq, wl);
2075 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002076 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077 wl->fw = NULL;
2078 kfree(wl->nvs);
2079 wl->nvs = NULL;
2080
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081 kfree(wl->fw_status);
2082 kfree(wl->tx_res_if);
2083
2084 ieee80211_free_hw(wl->hw);
2085
2086 return 0;
2087}
2088
2089
2090static struct spi_driver wl1271_spi_driver = {
2091 .driver = {
2092 .name = "wl1271",
2093 .bus = &spi_bus_type,
2094 .owner = THIS_MODULE,
2095 },
2096
2097 .probe = wl1271_probe,
2098 .remove = __devexit_p(wl1271_remove),
2099};
2100
2101static int __init wl1271_init(void)
2102{
2103 int ret;
2104
2105 ret = spi_register_driver(&wl1271_spi_driver);
2106 if (ret < 0) {
2107 wl1271_error("failed to register spi driver: %d", ret);
2108 goto out;
2109 }
2110
2111out:
2112 return ret;
2113}
2114
2115static void __exit wl1271_exit(void)
2116{
2117 spi_unregister_driver(&wl1271_spi_driver);
2118
2119 wl1271_notice("unloaded");
2120}
2121
2122module_init(wl1271_init);
2123module_exit(wl1271_exit);
2124
2125MODULE_LICENSE("GPL");
2126MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002127MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002128MODULE_FIRMWARE(WL1271_FW_NAME);