struct ieee80211_hw *cw1200_init_common(size_t priv_data_len, u8 *mac_addr) { int i; struct ieee80211_hw *hw; struct cw1200_common *priv; struct ieee80211_supported_band *sband; int band; hw = ieee80211_alloc_hw(priv_data_len, &cw1200_ops); if (!hw) return NULL; priv = hw->priv; priv->hw = hw; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->rates = cw1200_rates; /* TODO: fetch from FW */ priv->mcs_rates = cw1200_n_rates; /* Enable block ACK for every TID but voice. */ priv->ba_tid_mask = 0x3F; hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | /* Aggregation is fully controlled by firmware. * Do not need any support from the mac80211 stack */ /* IEEE80211_HW_AMPDU_AGGREGATION | */ #if defined(CONFIG_CW1200_USE_STE_EXTENSIONS) IEEE80211_HW_SUPPORTS_P2P_PS | IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS | IEEE80211_HW_SUPPORTS_CQM_TX_FAIL | #endif /* CONFIG_CW1200_USE_STE_EXTENSIONS */ IEEE80211_HW_BEACON_FILTER; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); /* Support only for limited wowlan functionalities */ hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT; hw->wiphy->wowlan.n_patterns = 0; #if defined(CONFIG_CW1200_USE_STE_EXTENSIONS) hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; #endif /* CONFIG_CW1200_USE_STE_EXTENSIONS */ #if defined(CONFIG_CW1200_DISABLE_BEACON_HINTS) hw->wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; #endif hw->channel_change_time = 1000; /* TODO: find actual value */ /* priv->beacon_req_id = cpu_to_le32(0); */ hw->queues = 4; priv->noise = -94; hw->max_rates = 8; hw->max_rate_tries = 15; hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ + 12 /* TKIP ICV and MIC */; hw->sta_data_size = sizeof(struct cw1200_sta_priv); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz; #ifdef CONFIG_CW1200_5GHZ_SUPPORT hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz; #endif /* CONFIG_CW1200_5GHZ_SUPPORT */ /* Channel params have to be cleared before registering wiphy again */ for (band = 0; band < IEEE80211_NUM_BANDS; band++) { sband = hw->wiphy->bands[band]; if (!sband) continue; for (i = 0; i < sband->n_channels; i++) { sband->channels[i].flags = 0; sband->channels[i].max_antenna_gain = 0; sband->channels[i].max_power = 30; } } hw->wiphy->max_scan_ssids = 2; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; SET_IEEE80211_PERM_ADDR(hw, mac_addr); if (hw->wiphy->perm_addr[3] == 0 && hw->wiphy->perm_addr[4] == 0 && hw->wiphy->perm_addr[5] == 0) { get_random_bytes(&hw->wiphy->perm_addr[3], 3); } mutex_init(&priv->wsm_cmd_mux); mutex_init(&priv->conf_mutex); priv->workqueue = create_singlethread_workqueue("cw1200_wq"); sema_init(&priv->scan.lock, 1); INIT_WORK(&priv->scan.work, cw1200_scan_work); INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout); INIT_DELAYED_WORK(&priv->clear_recent_scan_work, cw1200_clear_recent_scan_work); INIT_WORK(&priv->join_work, cw1200_join_work); INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout); INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work); INIT_WORK(&priv->offchannel_work, cw1200_offchannel_work); INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work); INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work); spin_lock_init(&priv->event_queue_lock); INIT_LIST_HEAD(&priv->event_queue); INIT_WORK(&priv->event_handler, cw1200_event_handler); INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work); INIT_DELAYED_WORK(&priv->connection_loss_work, cw1200_connection_loss_work); spin_lock_init(&priv->bss_loss_lock); INIT_WORK(&priv->tx_failure_work, cw1200_tx_failure_work); spin_lock_init(&priv->ps_state_lock); INIT_DELAYED_WORK(&priv->set_cts_work, cw1200_set_cts_work); INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work); INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work); INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work); INIT_WORK(&priv->link_id_work, cw1200_link_id_work); INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work); #if defined(CONFIG_CW1200_USE_STE_EXTENSIONS) INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset); #endif INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); INIT_WORK(&priv->set_beacon_wakeup_period_work, cw1200_set_beacon_wakeup_period_work); INIT_WORK(&priv->ba_work, cw1200_ba_work); init_timer(&priv->mcast_timeout); priv->mcast_timeout.data = (unsigned long)priv; priv->mcast_timeout.function = cw1200_mcast_timeout; spin_lock_init(&priv->ba_lock); init_timer(&priv->ba_timer); priv->ba_timer.data = (unsigned long)priv; priv->ba_timer.function = cw1200_ba_timer; if (unlikely(cw1200_queue_stats_init(&priv->tx_queue_stats, CW1200_LINK_ID_MAX, cw1200_skb_dtor, priv))) { ieee80211_free_hw(hw); return NULL; } for (i = 0; i < 4; ++i) { if (unlikely(cw1200_queue_init(&priv->tx_queue[i], &priv->tx_queue_stats, i, 16, cw1200_ttl[i]))) { for (; i > 0; i--) cw1200_queue_deinit(&priv->tx_queue[i - 1]); cw1200_queue_stats_deinit(&priv->tx_queue_stats); ieee80211_free_hw(hw); return NULL; } } init_waitqueue_head(&priv->channel_switch_done); init_waitqueue_head(&priv->wsm_cmd_wq); init_waitqueue_head(&priv->wsm_startup_done); wsm_buf_init(&priv->wsm_cmd_buf); spin_lock_init(&priv->wsm_cmd.lock); tx_policy_init(priv); #if defined(CONFIG_CW1200_WSM_DUMPS_SHORT) priv->wsm_dump_max_size = 20; #endif /* CONFIG_CW1200_WSM_DUMPS_SHORT */ return hw; }
static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, const bool have_5ghz) { int i, band; struct ieee80211_hw *hw; struct cw1200_common *priv; hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops); if (!hw) return NULL; priv = hw->priv; priv->hw = hw; priv->hw_type = -1; priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->rates = cw1200_rates; /* TODO: fetch from FW */ priv->mcs_rates = cw1200_n_rates; if (cw1200_ba_rx_tids != -1) priv->ba_rx_tid_mask = cw1200_ba_rx_tids; else priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */ if (cw1200_ba_tx_tids != -1) priv->ba_tx_tid_mask = cw1200_ba_tx_tids; else priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); #ifdef CONFIG_PM hw->wiphy->wowlan = &cw1200_wowlan_support; #endif hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; priv->rts_threshold = -1; hw->max_rates = 8; hw->max_rate_tries = 15; hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + 8; /* TKIP IV */ hw->sta_data_size = sizeof(struct cw1200_sta_priv); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz; if (have_5ghz) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz; /* Channel params have to be cleared before registering wiphy again */ for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; if (!sband) continue; for (i = 0; i < sband->n_channels; i++) { sband->channels[i].flags = 0; sband->channels[i].max_antenna_gain = 0; sband->channels[i].max_power = 30; } } hw->wiphy->max_scan_ssids = 2; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; if (macaddr) SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr); else SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template); /* Fix up mac address if necessary */ if (hw->wiphy->perm_addr[3] == 0 && hw->wiphy->perm_addr[4] == 0 && hw->wiphy->perm_addr[5] == 0) { get_random_bytes(&hw->wiphy->perm_addr[3], 3); } mutex_init(&priv->wsm_cmd_mux); mutex_init(&priv->conf_mutex); priv->workqueue = create_singlethread_workqueue("cw1200_wq"); sema_init(&priv->scan.lock, 1); INIT_WORK(&priv->scan.work, cw1200_scan_work); INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout); INIT_DELAYED_WORK(&priv->clear_recent_scan_work, cw1200_clear_recent_scan_work); INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout); INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work); INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work); INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work); INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work); spin_lock_init(&priv->event_queue_lock); INIT_LIST_HEAD(&priv->event_queue); INIT_WORK(&priv->event_handler, cw1200_event_handler); INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work); INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work); spin_lock_init(&priv->bss_loss_lock); spin_lock_init(&priv->ps_state_lock); INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work); INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work); INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work); INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work); INIT_WORK(&priv->link_id_work, cw1200_link_id_work); INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work); INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset); INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); INIT_WORK(&priv->set_beacon_wakeup_period_work, cw1200_set_beacon_wakeup_period_work); init_timer(&priv->mcast_timeout); priv->mcast_timeout.data = (unsigned long)priv; priv->mcast_timeout.function = cw1200_mcast_timeout; if (cw1200_queue_stats_init(&priv->tx_queue_stats, CW1200_LINK_ID_MAX, cw1200_skb_dtor, priv)) { ieee80211_free_hw(hw); return NULL; } for (i = 0; i < 4; ++i) { if (cw1200_queue_init(&priv->tx_queue[i], &priv->tx_queue_stats, i, 16, cw1200_ttl[i])) { for (; i > 0; i--) cw1200_queue_deinit(&priv->tx_queue[i - 1]); cw1200_queue_stats_deinit(&priv->tx_queue_stats); ieee80211_free_hw(hw); return NULL; } } init_waitqueue_head(&priv->channel_switch_done); init_waitqueue_head(&priv->wsm_cmd_wq); init_waitqueue_head(&priv->wsm_startup_done); init_waitqueue_head(&priv->ps_mode_switch_done); wsm_buf_init(&priv->wsm_cmd_buf); spin_lock_init(&priv->wsm_cmd.lock); priv->wsm_cmd.done = 1; tx_policy_init(priv); return hw; }