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