Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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/firmware.h>
 25#include <linux/etherdevice.h>
 26#include <linux/vmalloc.h>
 27#include <linux/random.h>
 28#include <linux/sched.h>
 29#include <net/mac80211.h>
 30
 31#include "cw1200.h"
 32#include "txrx.h"
 33#include "hwbus.h"
 34#include "fwio.h"
 35#include "hwio.h"
 36#include "bh.h"
 37#include "sta.h"
 38#include "scan.h"
 39#include "debug.h"
 40#include "pm.h"
 41
 42MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
 43MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code");
 44MODULE_LICENSE("GPL");
 45MODULE_ALIAS("cw1200_core");
 46
 47/* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */
 48static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00};
 49module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, 0444);
 50MODULE_PARM_DESC(macaddr, "Override platform_data MAC address");
 51
 52static char *cw1200_sdd_path;
 53module_param(cw1200_sdd_path, charp, 0644);
 54MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file");
 55static int cw1200_refclk;
 56module_param(cw1200_refclk, int, 0644);
 57MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock");
 58
 59int cw1200_power_mode = wsm_power_mode_quiescent;
 60module_param(cw1200_power_mode, int, 0644);
 61MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode.  0 == active, 1 == doze, 2 == quiescent (default)");
 62
 63#define RATETAB_ENT(_rate, _rateid, _flags)		\
 64	{						\
 65		.bitrate	= (_rate),		\
 66		.hw_value	= (_rateid),		\
 67		.flags		= (_flags),		\
 68	}
 69
 70static struct ieee80211_rate cw1200_rates[] = {
 71	RATETAB_ENT(10,  0,   0),
 72	RATETAB_ENT(20,  1,   0),
 73	RATETAB_ENT(55,  2,   0),
 74	RATETAB_ENT(110, 3,   0),
 75	RATETAB_ENT(60,  6,  0),
 76	RATETAB_ENT(90,  7,  0),
 77	RATETAB_ENT(120, 8,  0),
 78	RATETAB_ENT(180, 9,  0),
 79	RATETAB_ENT(240, 10, 0),
 80	RATETAB_ENT(360, 11, 0),
 81	RATETAB_ENT(480, 12, 0),
 82	RATETAB_ENT(540, 13, 0),
 83};
 84
 85static struct ieee80211_rate cw1200_mcs_rates[] = {
 86	RATETAB_ENT(65,  14, IEEE80211_TX_RC_MCS),
 87	RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS),
 88	RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS),
 89	RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS),
 90	RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS),
 91	RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS),
 92	RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS),
 93	RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS),
 94};
 95
 96#define cw1200_a_rates		(cw1200_rates + 4)
 97#define cw1200_a_rates_size	(ARRAY_SIZE(cw1200_rates) - 4)
 98#define cw1200_g_rates		(cw1200_rates + 0)
 99#define cw1200_g_rates_size	(ARRAY_SIZE(cw1200_rates))
100#define cw1200_n_rates		(cw1200_mcs_rates)
101#define cw1200_n_rates_size	(ARRAY_SIZE(cw1200_mcs_rates))
102
103
104#define CHAN2G(_channel, _freq, _flags) {			\
105	.band			= NL80211_BAND_2GHZ,		\
106	.center_freq		= (_freq),			\
107	.hw_value		= (_channel),			\
108	.flags			= (_flags),			\
109	.max_antenna_gain	= 0,				\
110	.max_power		= 30,				\
111}
112
113#define CHAN5G(_channel, _flags) {				\
114	.band			= NL80211_BAND_5GHZ,		\
115	.center_freq	= 5000 + (5 * (_channel)),		\
116	.hw_value		= (_channel),			\
117	.flags			= (_flags),			\
118	.max_antenna_gain	= 0,				\
119	.max_power		= 30,				\
120}
121
122static struct ieee80211_channel cw1200_2ghz_chantable[] = {
123	CHAN2G(1, 2412, 0),
124	CHAN2G(2, 2417, 0),
125	CHAN2G(3, 2422, 0),
126	CHAN2G(4, 2427, 0),
127	CHAN2G(5, 2432, 0),
128	CHAN2G(6, 2437, 0),
129	CHAN2G(7, 2442, 0),
130	CHAN2G(8, 2447, 0),
131	CHAN2G(9, 2452, 0),
132	CHAN2G(10, 2457, 0),
133	CHAN2G(11, 2462, 0),
134	CHAN2G(12, 2467, 0),
135	CHAN2G(13, 2472, 0),
136	CHAN2G(14, 2484, 0),
137};
138
139static struct ieee80211_channel cw1200_5ghz_chantable[] = {
140	CHAN5G(34, 0),		CHAN5G(36, 0),
141	CHAN5G(38, 0),		CHAN5G(40, 0),
142	CHAN5G(42, 0),		CHAN5G(44, 0),
143	CHAN5G(46, 0),		CHAN5G(48, 0),
144	CHAN5G(52, 0),		CHAN5G(56, 0),
145	CHAN5G(60, 0),		CHAN5G(64, 0),
146	CHAN5G(100, 0),		CHAN5G(104, 0),
147	CHAN5G(108, 0),		CHAN5G(112, 0),
148	CHAN5G(116, 0),		CHAN5G(120, 0),
149	CHAN5G(124, 0),		CHAN5G(128, 0),
150	CHAN5G(132, 0),		CHAN5G(136, 0),
151	CHAN5G(140, 0),		CHAN5G(149, 0),
152	CHAN5G(153, 0),		CHAN5G(157, 0),
153	CHAN5G(161, 0),		CHAN5G(165, 0),
154	CHAN5G(184, 0),		CHAN5G(188, 0),
155	CHAN5G(192, 0),		CHAN5G(196, 0),
156	CHAN5G(200, 0),		CHAN5G(204, 0),
157	CHAN5G(208, 0),		CHAN5G(212, 0),
158	CHAN5G(216, 0),
159};
160
161static struct ieee80211_supported_band cw1200_band_2ghz = {
162	.channels = cw1200_2ghz_chantable,
163	.n_channels = ARRAY_SIZE(cw1200_2ghz_chantable),
164	.bitrates = cw1200_g_rates,
165	.n_bitrates = cw1200_g_rates_size,
166	.ht_cap = {
167		.cap = IEEE80211_HT_CAP_GRN_FLD |
168			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
169			IEEE80211_HT_CAP_MAX_AMSDU,
170		.ht_supported = 1,
171		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
172		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
173		.mcs = {
174			.rx_mask[0] = 0xFF,
175			.rx_highest = __cpu_to_le16(0x41),
176			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
177		},
178	},
179};
180
181static struct ieee80211_supported_band cw1200_band_5ghz = {
182	.channels = cw1200_5ghz_chantable,
183	.n_channels = ARRAY_SIZE(cw1200_5ghz_chantable),
184	.bitrates = cw1200_a_rates,
185	.n_bitrates = cw1200_a_rates_size,
186	.ht_cap = {
187		.cap = IEEE80211_HT_CAP_GRN_FLD |
188			(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
189			IEEE80211_HT_CAP_MAX_AMSDU,
190		.ht_supported = 1,
191		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
192		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
193		.mcs = {
194			.rx_mask[0] = 0xFF,
195			.rx_highest = __cpu_to_le16(0x41),
196			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
197		},
198	},
199};
200
201static const unsigned long cw1200_ttl[] = {
202	1 * HZ,	/* VO */
203	2 * HZ,	/* VI */
204	5 * HZ, /* BE */
205	10 * HZ	/* BK */
206};
207
208static const struct ieee80211_ops cw1200_ops = {
209	.start			= cw1200_start,
210	.stop			= cw1200_stop,
211	.add_interface		= cw1200_add_interface,
212	.remove_interface	= cw1200_remove_interface,
213	.change_interface	= cw1200_change_interface,
214	.tx			= cw1200_tx,
215	.hw_scan		= cw1200_hw_scan,
216	.set_tim		= cw1200_set_tim,
217	.sta_notify		= cw1200_sta_notify,
218	.sta_add		= cw1200_sta_add,
219	.sta_remove		= cw1200_sta_remove,
220	.set_key		= cw1200_set_key,
221	.set_rts_threshold	= cw1200_set_rts_threshold,
222	.config			= cw1200_config,
223	.bss_info_changed	= cw1200_bss_info_changed,
224	.prepare_multicast	= cw1200_prepare_multicast,
225	.configure_filter	= cw1200_configure_filter,
226	.conf_tx		= cw1200_conf_tx,
227	.get_stats		= cw1200_get_stats,
228	.ampdu_action		= cw1200_ampdu_action,
229	.flush			= cw1200_flush,
230#ifdef CONFIG_PM
231	.suspend		= cw1200_wow_suspend,
232	.resume			= cw1200_wow_resume,
233#endif
234	/* Intentionally not offloaded:					*/
235	/*.channel_switch	= cw1200_channel_switch,		*/
236	/*.remain_on_channel	= cw1200_remain_on_channel,		*/
237	/*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel,	*/
238};
239
240static int cw1200_ba_rx_tids = -1;
241static int cw1200_ba_tx_tids = -1;
242module_param(cw1200_ba_rx_tids, int, 0644);
243module_param(cw1200_ba_tx_tids, int, 0644);
244MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
245MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
246
247#ifdef CONFIG_PM
248static const struct wiphy_wowlan_support cw1200_wowlan_support = {
249	/* Support only for limited wowlan functionalities */
250	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
251};
252#endif
253
254
255static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
256						const bool have_5ghz)
257{
258	int i, band;
259	struct ieee80211_hw *hw;
260	struct cw1200_common *priv;
261
262	hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
263	if (!hw)
264		return NULL;
265
266	priv = hw->priv;
267	priv->hw = hw;
268	priv->hw_type = -1;
269	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
270	priv->rates = cw1200_rates; /* TODO: fetch from FW */
271	priv->mcs_rates = cw1200_n_rates;
272	if (cw1200_ba_rx_tids != -1)
273		priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
274	else
275		priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
276	if (cw1200_ba_tx_tids != -1)
277		priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
278	else
279		priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
280
281	ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
282	ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
283	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
284	ieee80211_hw_set(hw, CONNECTION_MONITOR);
285	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
286	ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
287	ieee80211_hw_set(hw, SIGNAL_DBM);
288	ieee80211_hw_set(hw, SUPPORTS_PS);
289
290	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
291					  BIT(NL80211_IFTYPE_ADHOC) |
292					  BIT(NL80211_IFTYPE_AP) |
293					  BIT(NL80211_IFTYPE_MESH_POINT) |
294					  BIT(NL80211_IFTYPE_P2P_CLIENT) |
295					  BIT(NL80211_IFTYPE_P2P_GO);
296
297#ifdef CONFIG_PM
298	hw->wiphy->wowlan = &cw1200_wowlan_support;
299#endif
300
301	hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
302
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[NL80211_BAND_2GHZ] = &cw1200_band_2ghz;
315	if (have_5ghz)
316		hw->wiphy->bands[NL80211_BAND_5GHZ] = &cw1200_band_5ghz;
317
318	/* Channel params have to be cleared before registering wiphy again */
319	for (band = 0; band < NUM_NL80211_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	timer_setup(&priv->mcast_timeout, cw1200_mcast_timeout, 0);
377
378	if (cw1200_queue_stats_init(&priv->tx_queue_stats,
379				    CW1200_LINK_ID_MAX,
380				    cw1200_skb_dtor,
381				    priv)) {
382		ieee80211_free_hw(hw);
383		return NULL;
384	}
385
386	for (i = 0; i < 4; ++i) {
387		if (cw1200_queue_init(&priv->tx_queue[i],
388				      &priv->tx_queue_stats, i, 16,
389				      cw1200_ttl[i])) {
390			for (; i > 0; i--)
391				cw1200_queue_deinit(&priv->tx_queue[i - 1]);
392			cw1200_queue_stats_deinit(&priv->tx_queue_stats);
393			ieee80211_free_hw(hw);
394			return NULL;
395		}
396	}
397
398	init_waitqueue_head(&priv->channel_switch_done);
399	init_waitqueue_head(&priv->wsm_cmd_wq);
400	init_waitqueue_head(&priv->wsm_startup_done);
401	init_waitqueue_head(&priv->ps_mode_switch_done);
402	wsm_buf_init(&priv->wsm_cmd_buf);
403	spin_lock_init(&priv->wsm_cmd.lock);
404	priv->wsm_cmd.done = 1;
405	tx_policy_init(priv);
406
407	return hw;
408}
409
410static int cw1200_register_common(struct ieee80211_hw *dev)
411{
412	struct cw1200_common *priv = dev->priv;
413	int err;
414
415#ifdef CONFIG_PM
416	err = cw1200_pm_init(&priv->pm_state, priv);
417	if (err) {
418		pr_err("Cannot init PM. (%d).\n",
419		       err);
420		return err;
421	}
422#endif
423
424	err = ieee80211_register_hw(dev);
425	if (err) {
426		pr_err("Cannot register device (%d).\n",
427		       err);
428#ifdef CONFIG_PM
429		cw1200_pm_deinit(&priv->pm_state);
430#endif
431		return err;
432	}
433
434	cw1200_debug_init(priv);
435
436	pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
437	return 0;
438}
439
440static void cw1200_free_common(struct ieee80211_hw *dev)
441{
442	ieee80211_free_hw(dev);
443}
444
445static void cw1200_unregister_common(struct ieee80211_hw *dev)
446{
447	struct cw1200_common *priv = dev->priv;
448	int i;
449
450	ieee80211_unregister_hw(dev);
451
452	del_timer_sync(&priv->mcast_timeout);
453	cw1200_unregister_bh(priv);
454
455	cw1200_debug_release(priv);
456
457	mutex_destroy(&priv->conf_mutex);
458
459	wsm_buf_deinit(&priv->wsm_cmd_buf);
460
461	destroy_workqueue(priv->workqueue);
462	priv->workqueue = NULL;
463
464	if (priv->sdd) {
465		release_firmware(priv->sdd);
466		priv->sdd = NULL;
467	}
468
469	for (i = 0; i < 4; ++i)
470		cw1200_queue_deinit(&priv->tx_queue[i]);
471
472	cw1200_queue_stats_deinit(&priv->tx_queue_stats);
473#ifdef CONFIG_PM
474	cw1200_pm_deinit(&priv->pm_state);
475#endif
476}
477
478/* Clock is in KHz */
479u32 cw1200_dpll_from_clk(u16 clk_khz)
480{
481	switch (clk_khz) {
482	case 0x32C8: /* 13000 KHz */
483		return 0x1D89D241;
484	case 0x3E80: /* 16000 KHz */
485		return 0x000001E1;
486	case 0x41A0: /* 16800 KHz */
487		return 0x124931C1;
488	case 0x4B00: /* 19200 KHz */
489		return 0x00000191;
490	case 0x5DC0: /* 24000 KHz */
491		return 0x00000141;
492	case 0x6590: /* 26000 KHz */
493		return 0x0EC4F121;
494	case 0x8340: /* 33600 KHz */
495		return 0x092490E1;
496	case 0x9600: /* 38400 KHz */
497		return 0x100010C1;
498	case 0x9C40: /* 40000 KHz */
499		return 0x000000C1;
500	case 0xBB80: /* 48000 KHz */
501		return 0x000000A1;
502	case 0xCB20: /* 52000 KHz */
503		return 0x07627091;
504	default:
505		pr_err("Unknown Refclk freq (0x%04x), using 26000KHz\n",
506		       clk_khz);
507		return 0x0EC4F121;
508	}
509}
510
511int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
512		      struct hwbus_priv *hwbus,
513		      struct device *pdev,
514		      struct cw1200_common **core,
515		      int ref_clk, const u8 *macaddr,
516		      const char *sdd_path, bool have_5ghz)
517{
518	int err = -EINVAL;
519	struct ieee80211_hw *dev;
520	struct cw1200_common *priv;
521	struct wsm_operational_mode mode = {
522		.power_mode = cw1200_power_mode,
523		.disable_more_flag_usage = true,
524	};
525
526	dev = cw1200_init_common(macaddr, have_5ghz);
527	if (!dev)
528		goto err;
529
530	priv = dev->priv;
531	priv->hw_refclk = ref_clk;
532	if (cw1200_refclk)
533		priv->hw_refclk = cw1200_refclk;
534
535	priv->sdd_path = (char *)sdd_path;
536	if (cw1200_sdd_path)
537		priv->sdd_path = cw1200_sdd_path;
538
539	priv->hwbus_ops = hwbus_ops;
540	priv->hwbus_priv = hwbus;
541	priv->pdev = pdev;
542	SET_IEEE80211_DEV(priv->hw, pdev);
543
544	/* Pass struct cw1200_common back up */
545	*core = priv;
546
547	err = cw1200_register_bh(priv);
548	if (err)
549		goto err1;
550
551	err = cw1200_load_firmware(priv);
552	if (err)
553		goto err2;
554
555	if (wait_event_interruptible_timeout(priv->wsm_startup_done,
556					     priv->firmware_ready,
557					     3*HZ) <= 0) {
558		/* TODO: Need to find how to reset device
559		   in QUEUE mode properly.
560		*/
561		pr_err("Timeout waiting on device startup\n");
562		err = -ETIMEDOUT;
563		goto err2;
564	}
565
566	/* Set low-power mode. */
567	wsm_set_operational_mode(priv, &mode);
568
569	/* Enable multi-TX confirmation */
570	wsm_use_multi_tx_conf(priv, true);
571
572	err = cw1200_register_common(dev);
573	if (err)
574		goto err2;
575
576	return err;
577
578err2:
579	cw1200_unregister_bh(priv);
580err1:
581	cw1200_free_common(dev);
582err:
583	*core = NULL;
584	return err;
585}
586EXPORT_SYMBOL_GPL(cw1200_core_probe);
587
588void cw1200_core_release(struct cw1200_common *self)
589{
590	/* Disable device interrupts */
591	self->hwbus_ops->lock(self->hwbus_priv);
592	__cw1200_irq_enable(self, 0);
593	self->hwbus_ops->unlock(self->hwbus_priv);
594
595	/* And then clean up */
596	cw1200_unregister_common(self->hw);
597	cw1200_free_common(self->hw);
598	return;
599}
600EXPORT_SYMBOL_GPL(cw1200_core_release);