blob: 90a60c1147a8f60a4953fe684f2c4b69fa4849ac [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);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200381 clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300382}
383
384static void wl1271_power_on(struct wl1271 *wl)
385{
386 wl->set_power(true);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200387 set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
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;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200780 struct ieee80211_conf *conf = &hw->conf;
781 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
782 struct ieee80211_sta *sta = txinfo->control.sta;
783 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200785 /* peek into the rates configured in the STA entry */
786 spin_lock_irqsave(&wl->wl_lock, flags);
787 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
788 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
789 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
790 }
791 spin_unlock_irqrestore(&wl->wl_lock, flags);
792
793 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300794 skb_queue_tail(&wl->tx_queue, skb);
795
796 /*
797 * The chip specific setup must run before the first TX packet -
798 * before that, the tx_work will not be initialized!
799 */
800
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300801 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802
803 /*
804 * The workqueue is slow to process the tx_queue and we need stop
805 * the queue here, otherwise the queue will get too long.
806 */
807 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
808 ieee80211_stop_queues(wl->hw);
809
810 /*
811 * FIXME: this is racy, the variable is not properly
812 * protected. Maybe fix this by removing the stupid
813 * variable altogether and checking the real queue state?
814 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200815 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 }
817
818 return NETDEV_TX_OK;
819}
820
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300821static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
822 void *arg)
823{
824 struct net_device *dev;
825 struct wireless_dev *wdev;
826 struct wiphy *wiphy;
827 struct ieee80211_hw *hw;
828 struct wl1271 *wl;
829 struct wl1271 *wl_temp;
830 struct in_device *idev;
831 struct in_ifaddr *ifa = arg;
832 int ret = 0;
833
834 /* FIXME: this ugly function should probably be implemented in the
835 * mac80211, and here should only be a simple callback handling actual
836 * setting of the filters. Now we need to dig up references to
837 * various structures to gain access to what we need.
838 * Also, because of this, there is no "initial" setting of the filter
839 * in "op_start", because we don't want to dig up struct net_device
840 * there - the filter will be set upon first change of the interface
841 * IP address. */
842
843 dev = ifa->ifa_dev->dev;
844
845 wdev = dev->ieee80211_ptr;
846 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200847 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300848
849 wiphy = wdev->wiphy;
850 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200851 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300852
853 hw = wiphy_priv(wiphy);
854 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200855 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300856
857 /* Check that the interface is one supported by this driver. */
858 wl_temp = hw->priv;
859 list_for_each_entry(wl, &wl_list, list) {
860 if (wl == wl_temp)
861 break;
862 }
863 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200864 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300865
866 /* Get the interface IP address for the device. "ifa" will become
867 NULL if:
868 - there is no IPV4 protocol address configured
869 - there are multiple (virtual) IPV4 addresses configured
870 When "ifa" is NULL, filtering will be disabled.
871 */
872 ifa = NULL;
873 idev = dev->ip_ptr;
874 if (idev)
875 ifa = idev->ifa_list;
876
877 if (ifa && ifa->ifa_next)
878 ifa = NULL;
879
880 mutex_lock(&wl->mutex);
881
882 if (wl->state == WL1271_STATE_OFF)
883 goto out;
884
885 ret = wl1271_ps_elp_wakeup(wl, false);
886 if (ret < 0)
887 goto out;
888 if (ifa)
889 ret = wl1271_acx_arp_ip_filter(wl, true,
890 (u8 *)&ifa->ifa_address,
891 ACX_IPV4_VERSION);
892 else
893 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
894 ACX_IPV4_VERSION);
895 wl1271_ps_elp_sleep(wl);
896
897out:
898 mutex_unlock(&wl->mutex);
899
Luciano Coelho17d72652009-11-23 23:22:15 +0200900 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300901}
902
903static struct notifier_block wl1271_dev_notifier = {
904 .notifier_call = wl1271_dev_notify,
905};
906
907
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908static int wl1271_op_start(struct ieee80211_hw *hw)
909{
910 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200911 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912 int ret = 0;
913
914 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
915
916 mutex_lock(&wl->mutex);
917
918 if (wl->state != WL1271_STATE_OFF) {
919 wl1271_error("cannot start because not in off state: %d",
920 wl->state);
921 ret = -EBUSY;
922 goto out;
923 }
924
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200925 while (retries) {
926 retries--;
927 ret = wl1271_chip_wakeup(wl);
928 if (ret < 0)
929 goto power_off;
930
931 ret = wl1271_boot(wl);
932 if (ret < 0)
933 goto power_off;
934
935 ret = wl1271_hw_init(wl);
936 if (ret < 0)
937 goto irq_disable;
938
939 wl->state = WL1271_STATE_ON;
940 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 goto out;
942
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200943irq_disable:
944 wl1271_disable_interrupts(wl);
945 mutex_unlock(&wl->mutex);
946 /* Unlocking the mutex in the middle of handling is
947 inherently unsafe. In this case we deem it safe to do,
948 because we need to let any possibly pending IRQ out of
949 the system (and while we are WL1271_STATE_OFF the IRQ
950 work function will not do anything.) Also, any other
951 possible concurrent operations will fail due to the
952 current state, hence the wl1271 struct should be safe. */
953 cancel_work_sync(&wl->irq_work);
954 mutex_lock(&wl->mutex);
955power_off:
956 wl1271_power_off(wl);
957 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200959 wl1271_error("firmware boot failed despite %d retries",
960 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300961out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962 mutex_unlock(&wl->mutex);
963
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300964 if (!ret) {
965 list_add(&wl->list, &wl_list);
966 register_inetaddr_notifier(&wl1271_dev_notifier);
967 }
968
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 return ret;
970}
971
972static void wl1271_op_stop(struct ieee80211_hw *hw)
973{
974 struct wl1271 *wl = hw->priv;
975 int i;
976
977 wl1271_info("down");
978
979 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
980
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300981 unregister_inetaddr_notifier(&wl1271_dev_notifier);
982 list_del(&wl->list);
983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 mutex_lock(&wl->mutex);
985
986 WARN_ON(wl->state != WL1271_STATE_ON);
987
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200988 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 mutex_unlock(&wl->mutex);
990 ieee80211_scan_completed(wl->hw, true);
991 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 }
993
994 wl->state = WL1271_STATE_OFF;
995
996 wl1271_disable_interrupts(wl);
997
998 mutex_unlock(&wl->mutex);
999
1000 cancel_work_sync(&wl->irq_work);
1001 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 mutex_lock(&wl->mutex);
1004
1005 /* let's notify MAC80211 about the remaining pending TX frames */
1006 wl1271_tx_flush(wl);
1007 wl1271_power_off(wl);
1008
1009 memset(wl->bssid, 0, ETH_ALEN);
1010 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1011 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001013 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014
1015 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001016 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1018 wl->tx_blocks_available = 0;
1019 wl->tx_results_count = 0;
1020 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001021 wl->tx_security_last_seq = 0;
1022 wl->tx_security_seq_16 = 0;
1023 wl->tx_security_seq_32 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 wl->time_offset = 0;
1025 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001026 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1027 wl->sta_rate_set = 0;
1028 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 for (i = 0; i < NUM_TX_QUEUES; i++)
1031 wl->tx_blocks_freed[i] = 0;
1032
1033 wl1271_debugfs_reset(wl);
1034 mutex_unlock(&wl->mutex);
1035}
1036
1037static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1038 struct ieee80211_if_init_conf *conf)
1039{
1040 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 int ret = 0;
1042
John W. Linvillee5539bc2009-08-18 10:50:34 -04001043 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1044 conf->type, conf->mac_addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045
1046 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001047 if (wl->vif) {
1048 ret = -EBUSY;
1049 goto out;
1050 }
1051
1052 wl->vif = conf->vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
1054 switch (conf->type) {
1055 case NL80211_IFTYPE_STATION:
1056 wl->bss_type = BSS_TYPE_STA_BSS;
1057 break;
1058 case NL80211_IFTYPE_ADHOC:
1059 wl->bss_type = BSS_TYPE_IBSS;
1060 break;
1061 default:
1062 ret = -EOPNOTSUPP;
1063 goto out;
1064 }
1065
1066 /* FIXME: what if conf->mac_addr changes? */
1067
1068out:
1069 mutex_unlock(&wl->mutex);
1070 return ret;
1071}
1072
1073static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1074 struct ieee80211_if_init_conf *conf)
1075{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001076 struct wl1271 *wl = hw->priv;
1077
1078 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001080 wl->vif = NULL;
1081 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082}
1083
1084#if 0
1085static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1086 struct ieee80211_vif *vif,
1087 struct ieee80211_if_conf *conf)
1088{
1089 struct wl1271 *wl = hw->priv;
1090 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091 int ret;
1092
David S. Miller32646902009-09-17 10:18:30 -07001093 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1094 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1096 conf->ssid_len);
1097
1098 mutex_lock(&wl->mutex);
1099
1100 ret = wl1271_ps_elp_wakeup(wl, false);
1101 if (ret < 0)
1102 goto out;
1103
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001104 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1105 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1106
1107 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1108
1109 ret = wl1271_cmd_join(wl);
1110 if (ret < 0)
1111 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001113 ret = wl1271_cmd_build_null_data(wl);
1114 if (ret < 0)
1115 goto out_sleep;
1116 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001117
1118 wl->ssid_len = conf->ssid_len;
1119 if (wl->ssid_len)
1120 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122 if (conf->changed & IEEE80211_IFCC_BEACON) {
1123 beacon = ieee80211_beacon_get(hw, vif);
1124 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1125 beacon->data, beacon->len);
1126
1127 if (ret < 0) {
1128 dev_kfree_skb(beacon);
1129 goto out_sleep;
1130 }
1131
1132 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1133 beacon->data, beacon->len);
1134
1135 dev_kfree_skb(beacon);
1136
1137 if (ret < 0)
1138 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139 }
1140
1141out_sleep:
1142 wl1271_ps_elp_sleep(wl);
1143
1144out:
1145 mutex_unlock(&wl->mutex);
1146
1147 return ret;
1148}
1149#endif
1150
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001151static int wl1271_join_channel(struct wl1271 *wl, int channel)
1152{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001153 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001154 /* we need to use a dummy BSSID for now */
1155 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1156 0xad, 0xbe, 0xef };
1157
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001158 /* the dummy join is not required for ad-hoc */
1159 if (wl->bss_type == BSS_TYPE_IBSS)
1160 goto out;
1161
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001162 /* disable mac filter, so we hear everything */
1163 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1164
1165 wl->channel = channel;
1166 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1167
1168 ret = wl1271_cmd_join(wl);
1169 if (ret < 0)
1170 goto out;
1171
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001172 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001173
1174out:
1175 return ret;
1176}
1177
1178static int wl1271_unjoin_channel(struct wl1271 *wl)
1179{
1180 int ret;
1181
1182 /* to stop listening to a channel, we disconnect */
1183 ret = wl1271_cmd_disconnect(wl);
1184 if (ret < 0)
1185 goto out;
1186
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001187 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001188 wl->channel = 0;
1189 memset(wl->bssid, 0, ETH_ALEN);
1190 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1191
1192out:
1193 return ret;
1194}
1195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1197{
1198 struct wl1271 *wl = hw->priv;
1199 struct ieee80211_conf *conf = &hw->conf;
1200 int channel, ret = 0;
1201
1202 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1203
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001204 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205 channel,
1206 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001207 conf->power_level,
1208 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209
1210 mutex_lock(&wl->mutex);
1211
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001212 wl->band = conf->channel->band;
1213
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001214 ret = wl1271_ps_elp_wakeup(wl, false);
1215 if (ret < 0)
1216 goto out;
1217
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001218 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001219 if (conf->flags & IEEE80211_CONF_IDLE &&
1220 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001221 wl1271_unjoin_channel(wl);
1222 else
1223 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001224
1225 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001226 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1227 wl->sta_rate_set = 0;
1228 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001229 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001230 }
1231
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001232 /* if the channel changes while joined, join again */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001233 if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001234 wl1271_join_channel(wl, channel);
1235
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001236 if (conf->flags & IEEE80211_CONF_PS &&
1237 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1238 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239
1240 /*
1241 * We enter PSM only if we're already associated.
1242 * If we're not, we'll enter it when joining an SSID,
1243 * through the bss_info_changed() hook.
1244 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001245 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001246 wl1271_info("psm enabled");
1247 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
1248 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001249 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001250 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251 wl1271_info("psm disabled");
1252
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001253 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001255 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
1257 }
1258
1259 if (conf->power_level != wl->power_level) {
1260 ret = wl1271_acx_tx_power(wl, conf->power_level);
1261 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001262 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
1264 wl->power_level = conf->power_level;
1265 }
1266
1267out_sleep:
1268 wl1271_ps_elp_sleep(wl);
1269
1270out:
1271 mutex_unlock(&wl->mutex);
1272
1273 return ret;
1274}
1275
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001276struct wl1271_filter_params {
1277 bool enabled;
1278 int mc_list_length;
1279 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1280};
1281
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001282static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1283 struct dev_addr_list *mc_list)
1284{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001285 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001286 int i;
1287
Juuso Oikarinen74441132009-10-13 12:47:53 +03001288 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001289 if (!fp) {
1290 wl1271_error("Out of memory setting filters.");
1291 return 0;
1292 }
1293
1294 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001295 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001296 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1297 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001298 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001299 }
1300
1301 fp->mc_list_length = 0;
1302 for (i = 0; i < mc_count; i++) {
1303 if (mc_list->da_addrlen == ETH_ALEN) {
1304 memcpy(fp->mc_list[fp->mc_list_length],
1305 mc_list->da_addr, ETH_ALEN);
1306 fp->mc_list_length++;
1307 } else
1308 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001309 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001310 }
1311
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001312 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001313}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001315#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1316 FIF_ALLMULTI | \
1317 FIF_FCSFAIL | \
1318 FIF_BCN_PRBRESP_PROMISC | \
1319 FIF_CONTROL | \
1320 FIF_OTHER_BSS)
1321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1323 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001324 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001325{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001326 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001328 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329
1330 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1331
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001332 mutex_lock(&wl->mutex);
1333
1334 if (wl->state == WL1271_STATE_OFF)
1335 goto out;
1336
1337 ret = wl1271_ps_elp_wakeup(wl, false);
1338 if (ret < 0)
1339 goto out;
1340
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 *total &= WL1271_SUPPORTED_FILTERS;
1342 changed &= WL1271_SUPPORTED_FILTERS;
1343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 if (*total & FIF_ALLMULTI)
1345 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1346 else if (fp)
1347 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1348 fp->mc_list,
1349 fp->mc_list_length);
1350 if (ret < 0)
1351 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001353 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001354
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001355 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001356
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001357 /* determine, whether supported filter values have changed */
1358 if (changed == 0)
1359 goto out_sleep;
1360
1361 /* apply configured filters */
1362 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1363 if (ret < 0)
1364 goto out_sleep;
1365
1366out_sleep:
1367 wl1271_ps_elp_sleep(wl);
1368
1369out:
1370 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371}
1372
1373static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1374 struct ieee80211_vif *vif,
1375 struct ieee80211_sta *sta,
1376 struct ieee80211_key_conf *key_conf)
1377{
1378 struct wl1271 *wl = hw->priv;
1379 const u8 *addr;
1380 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001381 u32 tx_seq_32 = 0;
1382 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383 u8 key_type;
1384
1385 static const u8 bcast_addr[ETH_ALEN] =
1386 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1387
1388 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1389
1390 addr = sta ? sta->addr : bcast_addr;
1391
1392 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1393 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1394 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1395 key_conf->alg, key_conf->keyidx,
1396 key_conf->keylen, key_conf->flags);
1397 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1398
1399 if (is_zero_ether_addr(addr)) {
1400 /* We dont support TX only encryption */
1401 ret = -EOPNOTSUPP;
1402 goto out;
1403 }
1404
1405 mutex_lock(&wl->mutex);
1406
1407 ret = wl1271_ps_elp_wakeup(wl, false);
1408 if (ret < 0)
1409 goto out_unlock;
1410
1411 switch (key_conf->alg) {
1412 case ALG_WEP:
1413 key_type = KEY_WEP;
1414
1415 key_conf->hw_key_idx = key_conf->keyidx;
1416 break;
1417 case ALG_TKIP:
1418 key_type = KEY_TKIP;
1419
1420 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001421 tx_seq_32 = wl->tx_security_seq_32;
1422 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 break;
1424 case ALG_CCMP:
1425 key_type = KEY_AES;
1426
1427 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001428 tx_seq_32 = wl->tx_security_seq_32;
1429 tx_seq_16 = wl->tx_security_seq_16;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430 break;
1431 default:
1432 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1433
1434 ret = -EOPNOTSUPP;
1435 goto out_sleep;
1436 }
1437
1438 switch (cmd) {
1439 case SET_KEY:
1440 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1441 key_conf->keyidx, key_type,
1442 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001443 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 if (ret < 0) {
1445 wl1271_error("Could not add or replace key");
1446 goto out_sleep;
1447 }
1448 break;
1449
1450 case DISABLE_KEY:
1451 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1452 key_conf->keyidx, key_type,
1453 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001454 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 if (ret < 0) {
1456 wl1271_error("Could not remove key");
1457 goto out_sleep;
1458 }
1459 break;
1460
1461 default:
1462 wl1271_error("Unsupported key cmd 0x%x", cmd);
1463 ret = -EOPNOTSUPP;
1464 goto out_sleep;
1465
1466 break;
1467 }
1468
1469out_sleep:
1470 wl1271_ps_elp_sleep(wl);
1471
1472out_unlock:
1473 mutex_unlock(&wl->mutex);
1474
1475out:
1476 return ret;
1477}
1478
1479static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1480 struct cfg80211_scan_request *req)
1481{
1482 struct wl1271 *wl = hw->priv;
1483 int ret;
1484 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001485 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486
1487 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1488
1489 if (req->n_ssids) {
1490 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001491 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492 }
1493
1494 mutex_lock(&wl->mutex);
1495
1496 ret = wl1271_ps_elp_wakeup(wl, false);
1497 if (ret < 0)
1498 goto out;
1499
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001500 if (wl1271_11a_enabled())
1501 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1502 WL1271_SCAN_BAND_DUAL, 3);
1503 else
1504 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1505 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506
1507 wl1271_ps_elp_sleep(wl);
1508
1509out:
1510 mutex_unlock(&wl->mutex);
1511
1512 return ret;
1513}
1514
1515static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1516{
1517 struct wl1271 *wl = hw->priv;
1518 int ret;
1519
1520 mutex_lock(&wl->mutex);
1521
1522 ret = wl1271_ps_elp_wakeup(wl, false);
1523 if (ret < 0)
1524 goto out;
1525
1526 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1527 if (ret < 0)
1528 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1529
1530 wl1271_ps_elp_sleep(wl);
1531
1532out:
1533 mutex_unlock(&wl->mutex);
1534
1535 return ret;
1536}
1537
1538static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1539 struct ieee80211_vif *vif,
1540 struct ieee80211_bss_conf *bss_conf,
1541 u32 changed)
1542{
1543 enum wl1271_cmd_ps_mode mode;
1544 struct wl1271 *wl = hw->priv;
1545 int ret;
1546
1547 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1548
1549 mutex_lock(&wl->mutex);
1550
1551 ret = wl1271_ps_elp_wakeup(wl, false);
1552 if (ret < 0)
1553 goto out;
1554
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001555 if ((changed & BSS_CHANGED_BSSID) &&
1556 /*
1557 * Now we know the correct bssid, so we send a new join command
1558 * and enable the BSSID filter
1559 */
1560 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1561 wl->rx_config |= CFG_BSSID_FILTER_EN;
1562 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Luciano Coelhobdcbbb92009-12-11 15:40:48 +02001563 ret = wl1271_cmd_build_null_data(wl);
1564 if (ret < 0) {
1565 wl1271_warning("cmd buld null data failed %d",
1566 ret);
1567 goto out_sleep;
1568 }
Luciano Coelhocd264762009-12-11 15:40:47 +02001569 ret = wl1271_cmd_join(wl);
1570 if (ret < 0) {
1571 wl1271_warning("cmd join failed %d", ret);
1572 goto out_sleep;
1573 }
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001574 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001575 }
1576
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001577 if (wl->bss_type == BSS_TYPE_IBSS) {
1578 /* FIXME: This implements rudimentary ad-hoc support -
1579 proper templates are on the wish list and notification
1580 on when they change. This patch will update the templates
1581 on every call to this function. Also, the firmware will not
1582 answer to probe-requests as it does not have the proper
1583 SSID set in the JOIN command. The probe-response template
1584 is set nevertheless, as the FW will ASSERT without it */
1585 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1586
1587 if (beacon) {
1588 struct ieee80211_hdr *hdr;
1589 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1590 beacon->data,
1591 beacon->len);
1592
1593 if (ret < 0) {
1594 dev_kfree_skb(beacon);
1595 goto out_sleep;
1596 }
1597
1598 hdr = (struct ieee80211_hdr *) beacon->data;
1599 hdr->frame_control = cpu_to_le16(
1600 IEEE80211_FTYPE_MGMT |
1601 IEEE80211_STYPE_PROBE_RESP);
1602
1603 ret = wl1271_cmd_template_set(wl,
1604 CMD_TEMPL_PROBE_RESPONSE,
1605 beacon->data,
1606 beacon->len);
1607 dev_kfree_skb(beacon);
1608 if (ret < 0)
1609 goto out_sleep;
1610 }
1611 }
1612
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001613 if (changed & BSS_CHANGED_ASSOC) {
1614 if (bss_conf->assoc) {
1615 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001616 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001617
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001618 /*
1619 * with wl1271, we don't need to update the
1620 * beacon_int and dtim_period, because the firmware
1621 * updates it by itself when the first beacon is
1622 * received after a join.
1623 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001624 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1625 if (ret < 0)
1626 goto out_sleep;
1627
1628 ret = wl1271_acx_aid(wl, wl->aid);
1629 if (ret < 0)
1630 goto out_sleep;
1631
1632 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001633 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1634 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635 mode = STATION_POWER_SAVE_MODE;
1636 ret = wl1271_ps_set_mode(wl, mode);
1637 if (ret < 0)
1638 goto out_sleep;
1639 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001640 } else {
1641 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001642 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001643 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001644 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001646 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648 if (changed & BSS_CHANGED_ERP_SLOT) {
1649 if (bss_conf->use_short_slot)
1650 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1651 else
1652 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1653 if (ret < 0) {
1654 wl1271_warning("Set slot time failed %d", ret);
1655 goto out_sleep;
1656 }
1657 }
1658
1659 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1660 if (bss_conf->use_short_preamble)
1661 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1662 else
1663 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1664 }
1665
1666 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1667 if (bss_conf->use_cts_prot)
1668 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1669 else
1670 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1671 if (ret < 0) {
1672 wl1271_warning("Set ctsprotect failed %d", ret);
1673 goto out_sleep;
1674 }
1675 }
1676
1677out_sleep:
1678 wl1271_ps_elp_sleep(wl);
1679
1680out:
1681 mutex_unlock(&wl->mutex);
1682}
1683
1684
1685/* can't be const, mac80211 writes to this */
1686static struct ieee80211_rate wl1271_rates[] = {
1687 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001688 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1689 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001691 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1692 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1694 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001695 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1696 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1698 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001699 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1700 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001701 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1702 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001703 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1704 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001705 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001706 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1707 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001709 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1710 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001711 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001712 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1713 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001715 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1716 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001718 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1719 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001721 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1722 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001724 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1725 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726};
1727
1728/* can't be const, mac80211 writes to this */
1729static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001730 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1731 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1732 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1733 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1734 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1735 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1736 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1737 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1738 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1739 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1740 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1741 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1742 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001743};
1744
1745/* can't be const, mac80211 writes to this */
1746static struct ieee80211_supported_band wl1271_band_2ghz = {
1747 .channels = wl1271_channels,
1748 .n_channels = ARRAY_SIZE(wl1271_channels),
1749 .bitrates = wl1271_rates,
1750 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1751};
1752
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001753/* 5 GHz data rates for WL1273 */
1754static struct ieee80211_rate wl1271_rates_5ghz[] = {
1755 { .bitrate = 60,
1756 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1757 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1758 { .bitrate = 90,
1759 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1760 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1761 { .bitrate = 120,
1762 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1763 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1764 { .bitrate = 180,
1765 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1766 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1767 { .bitrate = 240,
1768 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1769 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1770 { .bitrate = 360,
1771 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1772 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1773 { .bitrate = 480,
1774 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1775 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1776 { .bitrate = 540,
1777 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1778 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1779};
1780
1781/* 5 GHz band channels for WL1273 */
1782static struct ieee80211_channel wl1271_channels_5ghz[] = {
1783 { .hw_value = 183, .center_freq = 4915},
1784 { .hw_value = 184, .center_freq = 4920},
1785 { .hw_value = 185, .center_freq = 4925},
1786 { .hw_value = 187, .center_freq = 4935},
1787 { .hw_value = 188, .center_freq = 4940},
1788 { .hw_value = 189, .center_freq = 4945},
1789 { .hw_value = 192, .center_freq = 4960},
1790 { .hw_value = 196, .center_freq = 4980},
1791 { .hw_value = 7, .center_freq = 5035},
1792 { .hw_value = 8, .center_freq = 5040},
1793 { .hw_value = 9, .center_freq = 5045},
1794 { .hw_value = 11, .center_freq = 5055},
1795 { .hw_value = 12, .center_freq = 5060},
1796 { .hw_value = 16, .center_freq = 5080},
1797 { .hw_value = 34, .center_freq = 5170},
1798 { .hw_value = 36, .center_freq = 5180},
1799 { .hw_value = 38, .center_freq = 5190},
1800 { .hw_value = 40, .center_freq = 5200},
1801 { .hw_value = 42, .center_freq = 5210},
1802 { .hw_value = 44, .center_freq = 5220},
1803 { .hw_value = 46, .center_freq = 5230},
1804 { .hw_value = 48, .center_freq = 5240},
1805 { .hw_value = 52, .center_freq = 5260},
1806 { .hw_value = 56, .center_freq = 5280},
1807 { .hw_value = 60, .center_freq = 5300},
1808 { .hw_value = 64, .center_freq = 5320},
1809 { .hw_value = 100, .center_freq = 5500},
1810 { .hw_value = 104, .center_freq = 5520},
1811 { .hw_value = 108, .center_freq = 5540},
1812 { .hw_value = 112, .center_freq = 5560},
1813 { .hw_value = 116, .center_freq = 5580},
1814 { .hw_value = 120, .center_freq = 5600},
1815 { .hw_value = 124, .center_freq = 5620},
1816 { .hw_value = 128, .center_freq = 5640},
1817 { .hw_value = 132, .center_freq = 5660},
1818 { .hw_value = 136, .center_freq = 5680},
1819 { .hw_value = 140, .center_freq = 5700},
1820 { .hw_value = 149, .center_freq = 5745},
1821 { .hw_value = 153, .center_freq = 5765},
1822 { .hw_value = 157, .center_freq = 5785},
1823 { .hw_value = 161, .center_freq = 5805},
1824 { .hw_value = 165, .center_freq = 5825},
1825};
1826
1827
1828static struct ieee80211_supported_band wl1271_band_5ghz = {
1829 .channels = wl1271_channels_5ghz,
1830 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1831 .bitrates = wl1271_rates_5ghz,
1832 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1833};
1834
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835static const struct ieee80211_ops wl1271_ops = {
1836 .start = wl1271_op_start,
1837 .stop = wl1271_op_stop,
1838 .add_interface = wl1271_op_add_interface,
1839 .remove_interface = wl1271_op_remove_interface,
1840 .config = wl1271_op_config,
1841/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001842 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 .configure_filter = wl1271_op_configure_filter,
1844 .tx = wl1271_op_tx,
1845 .set_key = wl1271_op_set_key,
1846 .hw_scan = wl1271_op_hw_scan,
1847 .bss_info_changed = wl1271_op_bss_info_changed,
1848 .set_rts_threshold = wl1271_op_set_rts_threshold,
1849};
1850
1851static int wl1271_register_hw(struct wl1271 *wl)
1852{
1853 int ret;
1854
1855 if (wl->mac80211_registered)
1856 return 0;
1857
1858 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
1859
1860 ret = ieee80211_register_hw(wl->hw);
1861 if (ret < 0) {
1862 wl1271_error("unable to register mac80211 hw: %d", ret);
1863 return ret;
1864 }
1865
1866 wl->mac80211_registered = true;
1867
1868 wl1271_notice("loaded");
1869
1870 return 0;
1871}
1872
1873static int wl1271_init_ieee80211(struct wl1271 *wl)
1874{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03001875 /* The tx descriptor buffer and the TKIP space. */
1876 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
1877 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001878
1879 /* unit us */
1880 /* FIXME: find a proper value */
1881 wl->hw->channel_change_time = 10000;
1882
1883 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03001884 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02001885 IEEE80211_HW_BEACON_FILTER |
1886 IEEE80211_HW_SUPPORTS_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001888 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1889 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001890 wl->hw->wiphy->max_scan_ssids = 1;
1891 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
1892
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001893 if (wl1271_11a_enabled())
1894 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
1895
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
1897
1898 return 0;
1899}
1900
1901static void wl1271_device_release(struct device *dev)
1902{
1903
1904}
1905
1906static struct platform_device wl1271_device = {
1907 .name = "wl1271",
1908 .id = -1,
1909
1910 /* device model insists to have a release function */
1911 .dev = {
1912 .release = wl1271_device_release,
1913 },
1914};
1915
1916#define WL1271_DEFAULT_CHANNEL 0
1917static int __devinit wl1271_probe(struct spi_device *spi)
1918{
1919 struct wl12xx_platform_data *pdata;
1920 struct ieee80211_hw *hw;
1921 struct wl1271 *wl;
1922 int ret, i;
1923 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
1924
1925 pdata = spi->dev.platform_data;
1926 if (!pdata) {
1927 wl1271_error("no platform data");
1928 return -ENODEV;
1929 }
1930
1931 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
1932 if (!hw) {
1933 wl1271_error("could not alloc ieee80211_hw");
1934 return -ENOMEM;
1935 }
1936
1937 wl = hw->priv;
1938 memset(wl, 0, sizeof(*wl));
1939
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001940 INIT_LIST_HEAD(&wl->list);
1941
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942 wl->hw = hw;
1943 dev_set_drvdata(&spi->dev, wl);
1944 wl->spi = spi;
1945
1946 skb_queue_head_init(&wl->tx_queue);
1947
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03001948 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001949 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 wl->rx_counter = 0;
1952 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1953 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001954 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001956 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001957 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1958 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001959 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001960 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001961 wl->flags = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03001963 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964 wl->tx_frames[i] = NULL;
1965
1966 spin_lock_init(&wl->wl_lock);
1967
1968 /*
1969 * In case our MAC address is not correctly set,
1970 * we use a random but Nokia MAC.
1971 */
1972 memcpy(wl->mac_addr, nokia_oui, 3);
1973 get_random_bytes(wl->mac_addr + 3, 3);
1974
1975 wl->state = WL1271_STATE_OFF;
1976 mutex_init(&wl->mutex);
1977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001978 /* This is the only SPI value that we need to set here, the rest
1979 * comes from the board-peripherals file */
1980 spi->bits_per_word = 32;
1981
1982 ret = spi_setup(spi);
1983 if (ret < 0) {
1984 wl1271_error("spi_setup failed");
1985 goto out_free;
1986 }
1987
1988 wl->set_power = pdata->set_power;
1989 if (!wl->set_power) {
1990 wl1271_error("set power function missing in platform data");
1991 ret = -ENODEV;
1992 goto out_free;
1993 }
1994
1995 wl->irq = spi->irq;
1996 if (wl->irq < 0) {
1997 wl1271_error("irq missing in platform data");
1998 ret = -ENODEV;
1999 goto out_free;
2000 }
2001
2002 ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
2003 if (ret < 0) {
2004 wl1271_error("request_irq() failed: %d", ret);
2005 goto out_free;
2006 }
2007
2008 set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
2009
2010 disable_irq(wl->irq);
2011
2012 ret = platform_device_register(&wl1271_device);
2013 if (ret) {
2014 wl1271_error("couldn't register platform device");
2015 goto out_irq;
2016 }
2017 dev_set_drvdata(&wl1271_device.dev, wl);
2018
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002019 /* Apply default driver configuration. */
2020 wl1271_conf_init(wl);
2021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 ret = wl1271_init_ieee80211(wl);
2023 if (ret)
2024 goto out_platform;
2025
2026 ret = wl1271_register_hw(wl);
2027 if (ret)
2028 goto out_platform;
2029
2030 wl1271_debugfs_init(wl);
2031
2032 wl1271_notice("initialized");
2033
2034 return 0;
2035
2036 out_platform:
2037 platform_device_unregister(&wl1271_device);
2038
2039 out_irq:
2040 free_irq(wl->irq, wl);
2041
2042 out_free:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002043 ieee80211_free_hw(hw);
2044
2045 return ret;
2046}
2047
2048static int __devexit wl1271_remove(struct spi_device *spi)
2049{
2050 struct wl1271 *wl = dev_get_drvdata(&spi->dev);
2051
2052 ieee80211_unregister_hw(wl->hw);
2053
2054 wl1271_debugfs_exit(wl);
2055 platform_device_unregister(&wl1271_device);
2056 free_irq(wl->irq, wl);
2057 kfree(wl->target_mem_map);
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03002058 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 wl->fw = NULL;
2060 kfree(wl->nvs);
2061 wl->nvs = NULL;
2062
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 kfree(wl->fw_status);
2064 kfree(wl->tx_res_if);
2065
2066 ieee80211_free_hw(wl->hw);
2067
2068 return 0;
2069}
2070
2071
2072static struct spi_driver wl1271_spi_driver = {
2073 .driver = {
2074 .name = "wl1271",
2075 .bus = &spi_bus_type,
2076 .owner = THIS_MODULE,
2077 },
2078
2079 .probe = wl1271_probe,
2080 .remove = __devexit_p(wl1271_remove),
2081};
2082
2083static int __init wl1271_init(void)
2084{
2085 int ret;
2086
2087 ret = spi_register_driver(&wl1271_spi_driver);
2088 if (ret < 0) {
2089 wl1271_error("failed to register spi driver: %d", ret);
2090 goto out;
2091 }
2092
2093out:
2094 return ret;
2095}
2096
2097static void __exit wl1271_exit(void)
2098{
2099 spi_unregister_driver(&wl1271_spi_driver);
2100
2101 wl1271_notice("unloaded");
2102}
2103
2104module_init(wl1271_init);
2105module_exit(wl1271_exit);
2106
2107MODULE_LICENSE("GPL");
2108MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
Luciano Coelho2f018722009-10-08 21:56:27 +03002109MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
Ben Hutchings49f146d2009-11-07 22:02:15 +00002110MODULE_FIRMWARE(WL1271_FW_NAME);