brcmfmac: support get_channel cfg80211 callback
authorRafał Miłecki <zajec5@gmail.com>
Fri, 20 May 2016 11:38:58 +0000 (13:38 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 14 Jun 2016 14:27:43 +0000 (17:27 +0300)
This is important for brcmfmac as some of released firmwares (e.g.
brcmfmac4366b-pcie.bin) may pick different channel than requested. This
has been tested with BCM4366B1 in D-Link DIR-885L.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c

index b044c7e48f915dd863c19b0154d88c4fe4d6218d..ba65a9315ac25fe20a89f343dcc40439c88b740b 100644 (file)
@@ -4907,6 +4907,68 @@ exit:
        return err;
 }
 
+static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
+                                     struct wireless_dev *wdev,
+                                     struct cfg80211_chan_def *chandef)
+{
+       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct net_device *ndev = wdev->netdev;
+       struct brcmf_if *ifp;
+       struct brcmu_chan ch;
+       enum nl80211_band band = 0;
+       enum nl80211_chan_width width = 0;
+       u32 chanspec;
+       int freq, err;
+
+       if (!ndev)
+               return -ENODEV;
+       ifp = netdev_priv(ndev);
+
+       err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
+       if (err) {
+               brcmf_err("chanspec failed (%d)\n", err);
+               return err;
+       }
+
+       ch.chspec = chanspec;
+       cfg->d11inf.decchspec(&ch);
+
+       switch (ch.band) {
+       case BRCMU_CHAN_BAND_2G:
+               band = NL80211_BAND_2GHZ;
+               break;
+       case BRCMU_CHAN_BAND_5G:
+               band = NL80211_BAND_5GHZ;
+               break;
+       }
+
+       switch (ch.bw) {
+       case BRCMU_CHAN_BW_80:
+               width = NL80211_CHAN_WIDTH_80;
+               break;
+       case BRCMU_CHAN_BW_40:
+               width = NL80211_CHAN_WIDTH_40;
+               break;
+       case BRCMU_CHAN_BW_20:
+               width = NL80211_CHAN_WIDTH_20;
+               break;
+       case BRCMU_CHAN_BW_80P80:
+               width = NL80211_CHAN_WIDTH_80P80;
+               break;
+       case BRCMU_CHAN_BW_160:
+               width = NL80211_CHAN_WIDTH_160;
+               break;
+       }
+
+       freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
+       chandef->chan = ieee80211_get_channel(wiphy, freq);
+       chandef->width = width;
+       chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band);
+       chandef->center_freq2 = 0;
+
+       return 0;
+}
+
 static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
                                           struct wireless_dev *wdev,
                                           enum nl80211_crit_proto_id proto,
@@ -5069,6 +5131,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
        .mgmt_tx = brcmf_cfg80211_mgmt_tx,
        .remain_on_channel = brcmf_p2p_remain_on_channel,
        .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
+       .get_channel = brcmf_cfg80211_get_channel,
        .start_p2p_device = brcmf_p2p_start_device,
        .stop_p2p_device = brcmf_p2p_stop_device,
        .crit_proto_start = brcmf_cfg80211_crit_proto_start,