linux/drivers/net/wireless/st/cw1200/main.c
<<
>>
Prefs
   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);
 601