]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/net/wireless/cw1200/main.c
cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets
[mirror_ubuntu-artful-kernel.git] / drivers / net / wireless / cw1200 / main.c
1 /*
2 * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
3 *
4 * Copyright (c) 2010, ST-Ericsson
5 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
6 *
7 * Based on:
8 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
9 * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
10 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
11 *
12 * Based on:
13 * - the islsm (softmac prism54) driver, which is:
14 * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
15 * - stlc45xx driver
16 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License version 2 as
20 * published by the Free Software Foundation.
21 */
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/firmware.h>
26 #include <linux/etherdevice.h>
27 #include <linux/vmalloc.h>
28 #include <linux/random.h>
29 #include <linux/sched.h>
30 #include <net/mac80211.h>
31
32 #include "cw1200.h"
33 #include "txrx.h"
34 #include "sbus.h"
35 #include "fwio.h"
36 #include "hwio.h"
37 #include "bh.h"
38 #include "sta.h"
39 #include "scan.h"
40 #include "debug.h"
41 #include "pm.h"
42
43 MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
44 MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code");
45 MODULE_LICENSE("GPL");
46 MODULE_ALIAS("cw1200_core");
47
48 /* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */
49 static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00};
50 module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, S_IRUGO);
51 MODULE_PARM_DESC(macaddr, "Override platform_data MAC address");
52
53 static char *cw1200_sdd_path;
54 module_param(cw1200_sdd_path, charp, 0644);
55 MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file");
56 static int cw1200_refclk;
57 module_param(cw1200_refclk, int, 0644);
58 MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock");
59
60 int cw1200_power_mode = wsm_power_mode_quiescent;
61 module_param(cw1200_power_mode, int, 0644);
62 MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode. 0 == active, 1 == doze, 2 == quiescent (default)");
63
64 #ifdef CONFIG_CW1200_ETF
65 int etf_mode;
66 module_param(etf_mode, int, 0644);
67 MODULE_PARM_DESC(etf_mode, "Enable EngineeringTestingFramework operation");
68 #endif
69
70 #define RATETAB_ENT(_rate, _rateid, _flags) \
71 { \
72 .bitrate = (_rate), \
73 .hw_value = (_rateid), \
74 .flags = (_flags), \
75 }
76
77 static struct ieee80211_rate cw1200_rates[] = {
78 RATETAB_ENT(10, 0, 0),
79 RATETAB_ENT(20, 1, 0),
80 RATETAB_ENT(55, 2, 0),
81 RATETAB_ENT(110, 3, 0),
82 RATETAB_ENT(60, 6, 0),
83 RATETAB_ENT(90, 7, 0),
84 RATETAB_ENT(120, 8, 0),
85 RATETAB_ENT(180, 9, 0),
86 RATETAB_ENT(240, 10, 0),
87 RATETAB_ENT(360, 11, 0),
88 RATETAB_ENT(480, 12, 0),
89 RATETAB_ENT(540, 13, 0),
90 };
91
92 static struct ieee80211_rate cw1200_mcs_rates[] = {
93 RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS),
94 RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS),
95 RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS),
96 RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS),
97 RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS),
98 RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS),
99 RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS),
100 RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS),
101 };
102
103 #define cw1200_a_rates (cw1200_rates + 4)
104 #define cw1200_a_rates_size (ARRAY_SIZE(cw1200_rates) - 4)
105 #define cw1200_g_rates (cw1200_rates + 0)
106 #define cw1200_g_rates_size (ARRAY_SIZE(cw1200_rates))
107 #define cw1200_n_rates (cw1200_mcs_rates)
108 #define cw1200_n_rates_size (ARRAY_SIZE(cw1200_mcs_rates))
109
110
111 #define CHAN2G(_channel, _freq, _flags) { \
112 .band = IEEE80211_BAND_2GHZ, \
113 .center_freq = (_freq), \
114 .hw_value = (_channel), \
115 .flags = (_flags), \
116 .max_antenna_gain = 0, \
117 .max_power = 30, \
118 }
119
120 #define CHAN5G(_channel, _flags) { \
121 .band = IEEE80211_BAND_5GHZ, \
122 .center_freq = 5000 + (5 * (_channel)), \
123 .hw_value = (_channel), \
124 .flags = (_flags), \
125 .max_antenna_gain = 0, \
126 .max_power = 30, \
127 }
128
129 static struct ieee80211_channel cw1200_2ghz_chantable[] = {
130 CHAN2G(1, 2412, 0),
131 CHAN2G(2, 2417, 0),
132 CHAN2G(3, 2422, 0),
133 CHAN2G(4, 2427, 0),
134 CHAN2G(5, 2432, 0),
135 CHAN2G(6, 2437, 0),
136 CHAN2G(7, 2442, 0),
137 CHAN2G(8, 2447, 0),
138 CHAN2G(9, 2452, 0),
139 CHAN2G(10, 2457, 0),
140 CHAN2G(11, 2462, 0),
141 CHAN2G(12, 2467, 0),
142 CHAN2G(13, 2472, 0),
143 CHAN2G(14, 2484, 0),
144 };
145
146 static struct ieee80211_channel cw1200_5ghz_chantable[] = {
147 CHAN5G(34, 0), CHAN5G(36, 0),
148 CHAN5G(38, 0), CHAN5G(40, 0),
149 CHAN5G(42, 0), CHAN5G(44, 0),
150 CHAN5G(46, 0), CHAN5G(48, 0),
151 CHAN5G(52, 0), CHAN5G(56, 0),
152 CHAN5G(60, 0), CHAN5G(64, 0),
153 CHAN5G(100, 0), CHAN5G(104, 0),
154 CHAN5G(108, 0), CHAN5G(112, 0),
155 CHAN5G(116, 0), CHAN5G(120, 0),
156 CHAN5G(124, 0), CHAN5G(128, 0),
157 CHAN5G(132, 0), CHAN5G(136, 0),
158 CHAN5G(140, 0), CHAN5G(149, 0),
159 CHAN5G(153, 0), CHAN5G(157, 0),
160 CHAN5G(161, 0), CHAN5G(165, 0),
161 CHAN5G(184, 0), CHAN5G(188, 0),
162 CHAN5G(192, 0), CHAN5G(196, 0),
163 CHAN5G(200, 0), CHAN5G(204, 0),
164 CHAN5G(208, 0), CHAN5G(212, 0),
165 CHAN5G(216, 0),
166 };
167
168 static struct ieee80211_supported_band cw1200_band_2ghz = {
169 .channels = cw1200_2ghz_chantable,
170 .n_channels = ARRAY_SIZE(cw1200_2ghz_chantable),
171 .bitrates = cw1200_g_rates,
172 .n_bitrates = cw1200_g_rates_size,
173 .ht_cap = {
174 .cap = IEEE80211_HT_CAP_GRN_FLD |
175 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
176 IEEE80211_HT_CAP_MAX_AMSDU,
177 .ht_supported = 1,
178 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
179 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
180 .mcs = {
181 .rx_mask[0] = 0xFF,
182 .rx_highest = __cpu_to_le16(0x41),
183 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
184 },
185 },
186 };
187
188 static struct ieee80211_supported_band cw1200_band_5ghz = {
189 .channels = cw1200_5ghz_chantable,
190 .n_channels = ARRAY_SIZE(cw1200_5ghz_chantable),
191 .bitrates = cw1200_a_rates,
192 .n_bitrates = cw1200_a_rates_size,
193 .ht_cap = {
194 .cap = IEEE80211_HT_CAP_GRN_FLD |
195 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
196 IEEE80211_HT_CAP_MAX_AMSDU,
197 .ht_supported = 1,
198 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
199 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
200 .mcs = {
201 .rx_mask[0] = 0xFF,
202 .rx_highest = __cpu_to_le16(0x41),
203 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
204 },
205 },
206 };
207
208 static const unsigned long cw1200_ttl[] = {
209 1 * HZ, /* VO */
210 2 * HZ, /* VI */
211 5 * HZ, /* BE */
212 10 * HZ /* BK */
213 };
214
215 static const struct ieee80211_ops cw1200_ops = {
216 .start = cw1200_start,
217 .stop = cw1200_stop,
218 .add_interface = cw1200_add_interface,
219 .remove_interface = cw1200_remove_interface,
220 .change_interface = cw1200_change_interface,
221 .tx = cw1200_tx,
222 .hw_scan = cw1200_hw_scan,
223 .set_tim = cw1200_set_tim,
224 .sta_notify = cw1200_sta_notify,
225 .sta_add = cw1200_sta_add,
226 .sta_remove = cw1200_sta_remove,
227 .set_key = cw1200_set_key,
228 .set_rts_threshold = cw1200_set_rts_threshold,
229 .config = cw1200_config,
230 .bss_info_changed = cw1200_bss_info_changed,
231 .prepare_multicast = cw1200_prepare_multicast,
232 .configure_filter = cw1200_configure_filter,
233 .conf_tx = cw1200_conf_tx,
234 .get_stats = cw1200_get_stats,
235 .ampdu_action = cw1200_ampdu_action,
236 .flush = cw1200_flush,
237 .suspend = cw1200_wow_suspend,
238 .resume = cw1200_wow_resume,
239 /* Intentionally not offloaded: */
240 /*.channel_switch = cw1200_channel_switch, */
241 /*.remain_on_channel = cw1200_remain_on_channel, */
242 /*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel, */
243 };
244
245 int cw1200_ba_rx_tids = -1;
246 int cw1200_ba_tx_tids = -1;
247 module_param(cw1200_ba_rx_tids, int, 0644);
248 module_param(cw1200_ba_tx_tids, int, 0644);
249 MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
250 MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
251
252 static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
253 const bool have_5ghz)
254 {
255 int i, band;
256 struct ieee80211_hw *hw;
257 struct cw1200_common *priv;
258
259 hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
260 if (!hw)
261 return NULL;
262
263 priv = hw->priv;
264 priv->hw = hw;
265 priv->hw_type = -1;
266 priv->mode = NL80211_IFTYPE_UNSPECIFIED;
267 priv->rates = cw1200_rates; /* TODO: fetch from FW */
268 priv->mcs_rates = cw1200_n_rates;
269 if (cw1200_ba_rx_tids != -1)
270 priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
271 else
272 priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
273 if (cw1200_ba_tx_tids != -1)
274 priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
275 else
276 priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
277
278 hw->flags = IEEE80211_HW_SIGNAL_DBM |
279 IEEE80211_HW_SUPPORTS_PS |
280 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
281 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
282 IEEE80211_HW_SUPPORTS_UAPSD |
283 IEEE80211_HW_CONNECTION_MONITOR |
284 IEEE80211_HW_AMPDU_AGGREGATION |
285 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
286 IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC;
287
288 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
289 BIT(NL80211_IFTYPE_ADHOC) |
290 BIT(NL80211_IFTYPE_AP) |
291 BIT(NL80211_IFTYPE_MESH_POINT) |
292 BIT(NL80211_IFTYPE_P2P_CLIENT) |
293 BIT(NL80211_IFTYPE_P2P_GO);
294
295 /* Support only for limited wowlan functionalities */
296 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
297 WIPHY_WOWLAN_DISCONNECT;
298 hw->wiphy->wowlan.n_patterns = 0;
299
300 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
301
302 hw->channel_change_time = 1000; /* TODO: find actual value */
303 hw->queues = 4;
304
305 priv->rts_threshold = -1;
306
307 hw->max_rates = 8;
308 hw->max_rate_tries = 15;
309 hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
310 8; /* TKIP IV */
311
312 hw->sta_data_size = sizeof(struct cw1200_sta_priv);
313
314 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz;
315 if (have_5ghz)
316 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz;
317
318 /* Channel params have to be cleared before registering wiphy again */
319 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
320 struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
321 if (!sband)
322 continue;
323 for (i = 0; i < sband->n_channels; i++) {
324 sband->channels[i].flags = 0;
325 sband->channels[i].max_antenna_gain = 0;
326 sband->channels[i].max_power = 30;
327 }
328 }
329
330 hw->wiphy->max_scan_ssids = 2;
331 hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
332
333 if (macaddr)
334 SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
335 else
336 SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
337
338 /* Fix up mac address if necessary */
339 if (hw->wiphy->perm_addr[3] == 0 &&
340 hw->wiphy->perm_addr[4] == 0 &&
341 hw->wiphy->perm_addr[5] == 0) {
342 get_random_bytes(&hw->wiphy->perm_addr[3], 3);
343 }
344
345 mutex_init(&priv->wsm_cmd_mux);
346 mutex_init(&priv->conf_mutex);
347 priv->workqueue = create_singlethread_workqueue("cw1200_wq");
348 sema_init(&priv->scan.lock, 1);
349 INIT_WORK(&priv->scan.work, cw1200_scan_work);
350 INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
351 INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
352 INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
353 cw1200_clear_recent_scan_work);
354 INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
355 INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
356 INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
357 INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
358 INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
359 spin_lock_init(&priv->event_queue_lock);
360 INIT_LIST_HEAD(&priv->event_queue);
361 INIT_WORK(&priv->event_handler, cw1200_event_handler);
362 INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
363 INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
364 spin_lock_init(&priv->bss_loss_lock);
365 spin_lock_init(&priv->ps_state_lock);
366 INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
367 INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
368 INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
369 INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
370 INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
371 INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
372 INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
373 INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
374 INIT_WORK(&priv->set_beacon_wakeup_period_work,
375 cw1200_set_beacon_wakeup_period_work);
376 init_timer(&priv->mcast_timeout);
377 priv->mcast_timeout.data = (unsigned long)priv;
378 priv->mcast_timeout.function = cw1200_mcast_timeout;
379
380 if (cw1200_queue_stats_init(&priv->tx_queue_stats,
381 CW1200_LINK_ID_MAX,
382 cw1200_skb_dtor,
383 priv)) {
384 ieee80211_free_hw(hw);
385 return NULL;
386 }
387
388 for (i = 0; i < 4; ++i) {
389 if (cw1200_queue_init(&priv->tx_queue[i],
390 &priv->tx_queue_stats, i, 16,
391 cw1200_ttl[i])) {
392 for (; i > 0; i--)
393 cw1200_queue_deinit(&priv->tx_queue[i - 1]);
394 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
395 ieee80211_free_hw(hw);
396 return NULL;
397 }
398 }
399
400 init_waitqueue_head(&priv->channel_switch_done);
401 init_waitqueue_head(&priv->wsm_cmd_wq);
402 init_waitqueue_head(&priv->wsm_startup_done);
403 init_waitqueue_head(&priv->ps_mode_switch_done);
404 wsm_buf_init(&priv->wsm_cmd_buf);
405 spin_lock_init(&priv->wsm_cmd.lock);
406 priv->wsm_cmd.done = 1;
407 tx_policy_init(priv);
408
409 return hw;
410 }
411
412 static int cw1200_register_common(struct ieee80211_hw *dev)
413 {
414 struct cw1200_common *priv = dev->priv;
415 int err;
416
417 #ifdef CONFIG_CW1200_ETF
418 if (etf_mode)
419 goto done;
420 #endif
421
422 err = cw1200_pm_init(&priv->pm_state, priv);
423 if (err) {
424 pr_err("Cannot init PM. (%d).\n",
425 err);
426 return err;
427 }
428
429 err = ieee80211_register_hw(dev);
430 if (err) {
431 pr_err("Cannot register device (%d).\n",
432 err);
433 cw1200_pm_deinit(&priv->pm_state);
434 return err;
435 }
436
437 #ifdef CONFIG_CW1200_ETF
438 done:
439 #endif
440 cw1200_debug_init(priv);
441
442 pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
443 return 0;
444 }
445
446 static void cw1200_free_common(struct ieee80211_hw *dev)
447 {
448 ieee80211_free_hw(dev);
449 }
450
451 static void cw1200_unregister_common(struct ieee80211_hw *dev)
452 {
453 struct cw1200_common *priv = dev->priv;
454 int i;
455
456 #ifdef CONFIG_CW1200_ETF
457 if (!etf_mode) {
458 #endif
459 ieee80211_unregister_hw(dev);
460 #ifdef CONFIG_CW1200_ETF
461 }
462 #endif
463
464 del_timer_sync(&priv->mcast_timeout);
465 cw1200_unregister_bh(priv);
466
467 cw1200_debug_release(priv);
468
469 mutex_destroy(&priv->conf_mutex);
470
471 wsm_buf_deinit(&priv->wsm_cmd_buf);
472
473 destroy_workqueue(priv->workqueue);
474 priv->workqueue = NULL;
475
476 if (priv->sdd) {
477 release_firmware(priv->sdd);
478 priv->sdd = NULL;
479 }
480
481 for (i = 0; i < 4; ++i)
482 cw1200_queue_deinit(&priv->tx_queue[i]);
483
484 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
485 cw1200_pm_deinit(&priv->pm_state);
486 }
487
488 /* Clock is in KHz */
489 u32 cw1200_dpll_from_clk(u16 clk_khz)
490 {
491 switch (clk_khz) {
492 case 0x32C8: /* 13000 KHz */
493 return 0x1D89D241;
494 case 0x3E80: /* 16000 KHz */
495 return 0x000001E1;
496 case 0x41A0: /* 16800 KHz */
497 return 0x124931C1;
498 case 0x4B00: /* 19200 KHz */
499 return 0x00000191;
500 case 0x5DC0: /* 24000 KHz */
501 return 0x00000141;
502 case 0x6590: /* 26000 KHz */
503 return 0x0EC4F121;
504 case 0x8340: /* 33600 KHz */
505 return 0x092490E1;
506 case 0x9600: /* 38400 KHz */
507 return 0x100010C1;
508 case 0x9C40: /* 40000 KHz */
509 return 0x000000C1;
510 case 0xBB80: /* 48000 KHz */
511 return 0x000000A1;
512 case 0xCB20: /* 52000 KHz */
513 return 0x07627091;
514 default:
515 pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n",
516 clk_khz);
517 return 0x0EC4F121;
518 }
519 }
520
521 int cw1200_core_probe(const struct sbus_ops *sbus_ops,
522 struct sbus_priv *sbus,
523 struct device *pdev,
524 struct cw1200_common **core,
525 int ref_clk, const u8 *macaddr,
526 const char *sdd_path, bool have_5ghz)
527 {
528 int err = -EINVAL;
529 struct ieee80211_hw *dev;
530 struct cw1200_common *priv;
531 struct wsm_operational_mode mode = {
532 .power_mode = cw1200_power_mode,
533 .disable_more_flag_usage = true,
534 };
535
536 dev = cw1200_init_common(macaddr, have_5ghz);
537 if (!dev)
538 goto err;
539
540 priv = dev->priv;
541 priv->hw_refclk = ref_clk;
542 if (cw1200_refclk)
543 priv->hw_refclk = cw1200_refclk;
544
545 priv->sdd_path = (char *)sdd_path;
546 if (cw1200_sdd_path)
547 priv->sdd_path = cw1200_sdd_path;
548
549 priv->sbus_ops = sbus_ops;
550 priv->sbus_priv = sbus;
551 priv->pdev = pdev;
552 SET_IEEE80211_DEV(priv->hw, pdev);
553
554 /* Pass struct cw1200_common back up */
555 *core = priv;
556
557 err = cw1200_register_bh(priv);
558 if (err)
559 goto err1;
560
561 #ifdef CONFIG_CW1200_ETF
562 if (etf_mode)
563 goto skip_fw;
564 #endif
565
566 err = cw1200_load_firmware(priv);
567 if (err)
568 goto err2;
569
570 if (wait_event_interruptible_timeout(priv->wsm_startup_done,
571 priv->firmware_ready,
572 3*HZ) <= 0) {
573 /* TODO: Need to find how to reset device
574 in QUEUE mode properly.
575 */
576 pr_err("Timeout waiting on device startup\n");
577 err = -ETIMEDOUT;
578 goto err2;
579 }
580
581 /* Set low-power mode. */
582 wsm_set_operational_mode(priv, &mode);
583
584 /* Enable multi-TX confirmation */
585 wsm_use_multi_tx_conf(priv, true);
586
587 #ifdef CONFIG_CW1200_ETF
588 skip_fw:
589 #endif
590 err = cw1200_register_common(dev);
591 if (err)
592 goto err2;
593
594 return err;
595
596 err2:
597 cw1200_unregister_bh(priv);
598 err1:
599 cw1200_free_common(dev);
600 err:
601 *core = NULL;
602 return err;
603 }
604 EXPORT_SYMBOL_GPL(cw1200_core_probe);
605
606 void cw1200_core_release(struct cw1200_common *self)
607 {
608 /* Disable device interrupts */
609 self->sbus_ops->lock(self->sbus_priv);
610 __cw1200_irq_enable(self, 0);
611 self->sbus_ops->unlock(self->sbus_priv);
612
613 /* And then clean up */
614 cw1200_unregister_common(self->hw);
615 cw1200_free_common(self->hw);
616 return;
617 }
618 EXPORT_SYMBOL_GPL(cw1200_core_release);