mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 21:36:52 +00:00
206 lines
5.2 KiB
C
206 lines
5.2 KiB
C
/*
|
|
* Copyright (C) 2015 Felix Fietkau <[email protected]>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#include "mt76.h"
|
|
|
|
#define CHAN2G(_idx, _freq) { \
|
|
.band = IEEE80211_BAND_2GHZ, \
|
|
.center_freq = (_freq), \
|
|
.hw_value = (_idx), \
|
|
.max_power = 30, \
|
|
}
|
|
|
|
#define CHAN5G(_idx, _freq) { \
|
|
.band = IEEE80211_BAND_5GHZ, \
|
|
.center_freq = (_freq), \
|
|
.hw_value = (_idx), \
|
|
.max_power = 30, \
|
|
}
|
|
|
|
static const struct ieee80211_channel mt76_channels_2ghz[] = {
|
|
CHAN2G(1, 2412),
|
|
CHAN2G(2, 2417),
|
|
CHAN2G(3, 2422),
|
|
CHAN2G(4, 2427),
|
|
CHAN2G(5, 2432),
|
|
CHAN2G(6, 2437),
|
|
CHAN2G(7, 2442),
|
|
CHAN2G(8, 2447),
|
|
CHAN2G(9, 2452),
|
|
CHAN2G(10, 2457),
|
|
CHAN2G(11, 2462),
|
|
CHAN2G(12, 2467),
|
|
CHAN2G(13, 2472),
|
|
CHAN2G(14, 2484),
|
|
};
|
|
|
|
static const struct ieee80211_channel mt76_channels_5ghz[] = {
|
|
CHAN5G(36, 5180),
|
|
CHAN5G(40, 5200),
|
|
CHAN5G(44, 5220),
|
|
CHAN5G(48, 5240),
|
|
|
|
CHAN5G(52, 5260),
|
|
CHAN5G(56, 5280),
|
|
CHAN5G(60, 5300),
|
|
CHAN5G(64, 5320),
|
|
|
|
CHAN5G(100, 5500),
|
|
CHAN5G(104, 5520),
|
|
CHAN5G(108, 5540),
|
|
CHAN5G(112, 5560),
|
|
CHAN5G(116, 5580),
|
|
CHAN5G(120, 5600),
|
|
CHAN5G(124, 5620),
|
|
CHAN5G(128, 5640),
|
|
CHAN5G(132, 5660),
|
|
CHAN5G(136, 5680),
|
|
CHAN5G(140, 5700),
|
|
|
|
CHAN5G(149, 5745),
|
|
CHAN5G(153, 5765),
|
|
CHAN5G(157, 5785),
|
|
CHAN5G(161, 5805),
|
|
CHAN5G(165, 5825),
|
|
};
|
|
|
|
static int
|
|
mt76_init_sband(struct mt76_dev *dev, struct ieee80211_supported_band *sband,
|
|
const struct ieee80211_channel *chan, int n_chan,
|
|
struct ieee80211_rate *rates, int n_rates, bool vht)
|
|
{
|
|
struct ieee80211_sta_ht_cap *ht_cap;
|
|
struct ieee80211_sta_vht_cap *vht_cap;
|
|
void *chanlist;
|
|
u16 mcs_map;
|
|
int size;
|
|
|
|
size = n_chan * sizeof(*chan);
|
|
chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
|
|
if (!chanlist)
|
|
return -ENOMEM;
|
|
|
|
sband->channels = chanlist;
|
|
sband->n_channels = n_chan;
|
|
sband->bitrates = rates;
|
|
sband->n_bitrates = n_rates;
|
|
|
|
ht_cap = &sband->ht_cap;
|
|
ht_cap->ht_supported = true;
|
|
ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
|
IEEE80211_HT_CAP_GRN_FLD |
|
|
IEEE80211_HT_CAP_SGI_20 |
|
|
IEEE80211_HT_CAP_SGI_40 |
|
|
IEEE80211_HT_CAP_LDPC_CODING |
|
|
IEEE80211_HT_CAP_TX_STBC |
|
|
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
|
|
|
|
ht_cap->mcs.rx_mask[0] = 0xff;
|
|
ht_cap->mcs.rx_mask[1] = 0xff;
|
|
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
|
ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
|
ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
|
|
|
|
if (!vht)
|
|
return 0;
|
|
|
|
vht_cap = &sband->vht_cap;
|
|
vht_cap->vht_supported = true;
|
|
|
|
mcs_map = (IEEE80211_VHT_MCS_SUPPORT_0_9 << (0 * 2)) |
|
|
(IEEE80211_VHT_MCS_SUPPORT_0_9 << (1 * 2)) |
|
|
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * 2)) |
|
|
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (3 * 2)) |
|
|
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (4 * 2)) |
|
|
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (5 * 2)) |
|
|
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (6 * 2)) |
|
|
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (7 * 2));
|
|
|
|
vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
|
|
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
|
|
vht_cap->cap = IEEE80211_VHT_CAP_RXLDPC |
|
|
IEEE80211_VHT_CAP_TXSTBC |
|
|
IEEE80211_VHT_CAP_RXSTBC_1 |
|
|
IEEE80211_VHT_CAP_SHORT_GI_80;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
|
|
int n_rates)
|
|
{
|
|
dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &dev->sband_2g;
|
|
|
|
return mt76_init_sband(dev, &dev->sband_2g,
|
|
mt76_channels_2ghz,
|
|
ARRAY_SIZE(mt76_channels_2ghz),
|
|
rates, n_rates, false);
|
|
}
|
|
|
|
static int
|
|
mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
|
|
int n_rates, bool vht)
|
|
{
|
|
dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &dev->sband_5g;
|
|
|
|
return mt76_init_sband(dev, &dev->sband_5g,
|
|
mt76_channels_5ghz,
|
|
ARRAY_SIZE(mt76_channels_5ghz),
|
|
rates, n_rates, vht);
|
|
}
|
|
|
|
int mt76_register_device(struct mt76_dev *dev, bool vht,
|
|
struct ieee80211_rate *rates, int n_rates)
|
|
{
|
|
struct ieee80211_hw *hw = dev->hw;
|
|
struct wiphy *wiphy = hw->wiphy;
|
|
int ret;
|
|
|
|
SET_IEEE80211_DEV(hw, dev->dev);
|
|
|
|
wiphy->interface_modes =
|
|
BIT(NL80211_IFTYPE_STATION) |
|
|
BIT(NL80211_IFTYPE_AP) |
|
|
#ifdef CONFIG_MAC80211_MESH
|
|
BIT(NL80211_IFTYPE_MESH_POINT) |
|
|
#endif
|
|
BIT(NL80211_IFTYPE_ADHOC);
|
|
|
|
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
|
|
|
|
hw->txq_data_size = sizeof(struct mt76_txq);
|
|
|
|
ieee80211_hw_set(hw, SIGNAL_DBM);
|
|
ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
|
|
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
|
|
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
|
|
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
|
|
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
|
|
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
|
|
|
|
if (dev->cap.has_2ghz) {
|
|
ret = mt76_init_sband_2g(dev, rates, n_rates);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
if (dev->cap.has_5ghz) {
|
|
ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return ieee80211_register_hw(hw);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mt76_register_device);
|