From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmwifi_channels.c | 733 ++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 498 insertions(+), 235 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmwifi_channels.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmwifi_channels.c index 3a138ed..18747aa 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmwifi_channels.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/bcmwifi_channels.c @@ -1,17 +1,18 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Misc utility routines used by kernel or app-level. * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -19,7 +20,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -27,7 +28,7 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ + * $Id: bcmwifi_channels.c 695288 2017-04-19 17:20:39Z $ */ #include <bcm_cfg.h> @@ -44,19 +45,21 @@ #include <ctype.h> #ifndef ASSERT #define ASSERT(exp) -#endif +#endif // endif #endif /* BCMDRIVER */ #include <bcmwifi_channels.h> #if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) #include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ -#endif +#endif // endif -/* Definitions for D11AC capable Chanspec type */ +#include <802.11.h> -/* Chanspec ASCII representation with 802.11ac capability: - * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]] +/* Definitions for D11AC capable (80MHz+) Chanspec type */ + +/* Chanspec ASCII representation: + * [<band> 'g'] <channel> ['/'<bandwidth> [<primary-sideband>]['/'<1st80channel>'-'<2nd80channel>]] * * <band>: * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. @@ -82,18 +85,18 @@ * <1st80Channel>: * <2nd80Channel>: * Required for 80+80, otherwise not allowed. - * Specifies the center channel of the first and second 80MHz band. + * Specifies the center channel of the primary and secondary 80MHz band. * * In its simplest form, it is a 20MHz channel number, with the implied band * of 2.4GHz if channel number <= 14, and 5GHz otherwise. * * To allow for backward compatibility with scripts, the old form for - * 40MHz channels is also allowed: <channel><ctl-sideband> + * 40MHz channels is also allowed: <channel><primary-sideband> * * <channel>: * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz - * <ctl-sideband>: - * "U" for upper, "L" for lower (or lower case "u" "l") + * <primary-sideband>: + * "U" for upper, "L" for lower (or lower case "u" "l") * * 5 GHz Examples: * Chanspec BW Center Ch Channel Range Primary Ch @@ -130,11 +133,7 @@ "80", "160", "80+80", -#ifdef WL11ULB - "2.5" -#else /* WL11ULB */ "na" -#endif /* WL11ULB */ }; static const uint8 wf_chspec_bw_mhz[] = @@ -145,13 +144,13 @@ /* 40MHz channels in 5GHz band */ static const uint8 wf_5g_40m_chans[] = -{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; +{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159, 167, 175}; #define WF_NUM_5G_40M_CHANS \ (sizeof(wf_5g_40m_chans)/sizeof(uint8)) /* 80MHz channels in 5GHz band */ static const uint8 wf_5g_80m_chans[] = -{42, 58, 106, 122, 138, 155}; +{42, 58, 106, 122, 138, 155, 171}; #define WF_NUM_5G_80M_CHANS \ (sizeof(wf_5g_80m_chans)/sizeof(uint8)) @@ -161,10 +160,82 @@ #define WF_NUM_5G_160M_CHANS \ (sizeof(wf_5g_160m_chans)/sizeof(uint8)) +/* Based on IEEE 802.11ax D6.1 */ +/* 40MHz channels in 6GHz band */ +static const uint8 wf_6g_40m_chans[] = +{3, 11, 19, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, +107, 115, 123, 131, 139, 147, 155, 163, 171, 179, +187, 195, 203, 211, 219, 227}; +#define WF_NUM_6G_40M_CHANS \ + (sizeof(wf_6g_40m_chans)/sizeof(uint8)) -/* convert bandwidth from chanspec to MHz */ -static uint -bw_chspec_to_mhz(chanspec_t chspec) +/* 80MHz channels in 6GHz band */ +static const uint8 wf_6g_80m_chans[] = +{7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 167, 183, +199, 215}; +#define WF_NUM_6G_80M_CHANS \ + (sizeof(wf_6g_80m_chans)/sizeof(uint8)) + +/* 160MHz channels in 6GHz band */ +static const uint8 wf_6g_160m_chans[] = +{15, 47, 79, 111, 143, 175, 207}; +#define WF_NUM_6G_160M_CHANS \ + (sizeof(wf_6g_160m_chans)/sizeof(uint8)) + +/* 6GHz PSC channels */ +uint8 wf_6g_psc_chans[] = +{5, 21, 37, 53, 69, 85, 101, 117, 133, 149, 165, 181, +197, 213, 229}; +#define WF_NUM_6G_PSC_CHANS \ + (sizeof(wf_6g_psc_chans)/sizeof(uint8)) + +/* opclass and channel information for US. Table E-1 */ +static const uint16 opclass_data[] = { + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), + 0, + 0, + 0, + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), + (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), + (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), + (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), +}; + +/** + * Return the chanspec bandwidth in MHz + * Bandwidth of 160 MHz will be returned for 80+80MHz chanspecs. + * + * @param chspec chanspec_t + * + * @return bandwidth of chspec in MHz units + */ +uint +wf_bw_chspec_to_mhz(chanspec_t chspec) { uint bw; @@ -194,34 +265,34 @@ return (uint8)(center_ch - center_chan_to_edge(bw)); } -/* return side band number given center channel and control channel +/* return side band number given center channel and primary20 channel * return -1 on error */ static int -channel_to_sb(uint center_ch, uint ctl_ch, uint bw) +channel_to_sb(uint center_ch, uint primary_ch, uint bw) { uint lowest = channel_low_edge(center_ch, bw); uint sb; - if ((ctl_ch - lowest) % 4) { - /* bad ctl channel, not mult 4 */ + if ((primary_ch - lowest) % 4) { + /* bad primary channel, not mult 4 */ return -1; } - sb = ((ctl_ch - lowest) / 4); + sb = ((primary_ch - lowest) / 4); /* sb must be a index to a 20MHz channel in range */ if (sb >= (bw / 20)) { - /* ctl_ch must have been too high for the center_ch */ + /* primary_ch must have been too high for the center_ch */ return -1; } - return sb; + return (int)sb; } -/* return control channel given center channel and side band */ +/* return primary20 channel given center channel and side band */ static uint8 -channel_to_ctl_chan(uint center_ch, uint bw, uint sb) +channel_to_primary20_chan(uint center_ch, uint bw, uint sb) { return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); } @@ -235,7 +306,7 @@ uint i; for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { if (ch == wf_5g_80m_chans[i]) - return i; + return (int)i; } return -1; @@ -262,7 +333,7 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf) { const char *band; - uint ctl_chan; + uint pri_chan; if (wf_chspec_malformed(chspec)) return NULL; @@ -274,32 +345,32 @@ (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; - /* ctl channel */ - ctl_chan = wf_chspec_ctlchan(chspec); + /* primary20 channel */ + pri_chan = wf_chspec_primary20_chan(chspec); - /* bandwidth and ctl sideband */ + /* bandwidth and primary20 sideband */ if (CHSPEC_IS20(chspec)) { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); + snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, pri_chan); } else if (!CHSPEC_IS8080(chspec)) { const char *bw; const char *sb = ""; - bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; + bw = wf_chspec_to_bw_str(chspec); #ifdef CHANSPEC_NEW_40MHZ_FORMAT - /* ctl sideband string if needed for 2g 40MHz */ + /* primary20 sideband string if needed for 2g 40MHz */ if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; } - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, pri_chan, bw, sb); #else - /* ctl sideband string instead of BW for 40MHz */ + /* primary20 sideband string instead of BW for 40MHz */ if (CHSPEC_IS40(chspec)) { sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); + snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, pri_chan, sb); } else { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); + snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, pri_chan, bw); } #endif /* CHANSPEC_NEW_40MHZ_FORMAT */ @@ -313,7 +384,7 @@ chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ - snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); + snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", pri_chan, chan1, chan2); } return (buf); @@ -339,14 +410,15 @@ } /* given a chanspec string, convert to a chanspec. + * if bandwidth not specified in chanspec input string, then use default_bw as bandwidth. * On error return 0 */ chanspec_t -wf_chspec_aton(const char *a) +wf_chspec_aton_ex(const char *a, const uint default_bw) { chanspec_t chspec; uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; - uint num, ctl_ch; + uint num, pri_ch; uint ch1, ch2; char c, sb_ul = '\0'; int i; @@ -359,7 +431,7 @@ if (!read_uint(&a, &num)) return 0; /* if we are looking at a 'g', then the first number was a band */ - c = tolower((int)a[0]); + c = tolower(a[0]); if (c == 'g') { a++; /* consume the char */ @@ -372,21 +444,22 @@ return 0; /* read the channel number */ - if (!read_uint(&a, &ctl_ch)) + if (!read_uint(&a, &pri_ch)) return 0; - c = tolower((int)a[0]); + c = tolower(a[0]); } else { /* first number is channel, use default for band */ - ctl_ch = num; - chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? + pri_ch = num; + chspec_band = ((pri_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); } if (c == '\0') { - /* default BW of 20MHz */ - chspec_bw = WL_CHANSPEC_BW_20; + /* bandwidth not specified in chanspec input string, so use default_bw bandwidth */ + chspec_bw = default_bw; + bw = wf_bw_chspec_to_mhz(default_bw); goto done_read; } @@ -408,9 +481,7 @@ return 0; /* convert to chspec value */ - if (bw == 2) { - chspec_bw = WL_CHANSPEC_BW_2P5; - } else if (bw == 5) { + if (bw == 5) { chspec_bw = WL_CHANSPEC_BW_5; } else if (bw == 10) { chspec_bw = WL_CHANSPEC_BW_10; @@ -428,11 +499,10 @@ /* So far we have <band>g<chan>/<bw> * Can now be followed by u/l if bw = 40, - * or '+80' if bw = 80, to make '80+80' bw, - * or '.5' if bw = 2.5 to make '2.5' bw . + * or '+80' if bw = 80, to make '80+80' bw. */ - c = tolower((int)a[0]); + c = (char)tolower((int)a[0]); /* if we have a 2g/40 channel, we should have a l/u spec now */ if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { @@ -474,19 +544,6 @@ /* read secondary 80MHz channel */ if (!read_uint(&a, &ch2)) return 0; - } else if (c == '.') { - /* 2.5 */ - /* must be looking at '.5' - * check and consume this string. - */ - chspec_bw = WL_CHANSPEC_BW_2P5; - - a ++; /* consume the char '.' */ - - /* consume the '5' string */ - if (*a++ != '5') { - return 0; - } } done_read: @@ -500,9 +557,9 @@ return 0; /* Now have all the chanspec string parts read; - * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. + * chspec_band, pri_ch, chspec_bw, sb_ul, ch1, ch2. * chspec_band and chspec_bw are chanspec values. - * Need to convert ctl_ch, sb_ul, and ch1,ch2 into + * Need to convert pri_ch, sb_ul, and ch1,ch2 into * a center channel (or two) and sideband. */ @@ -511,23 +568,23 @@ */ if (sb_ul != '\0') { if (sb_ul == 'l') { - chspec_ch = UPPER_20_SB(ctl_ch); + chspec_ch = UPPER_20_SB(pri_ch); chspec_sb = WL_CHANSPEC_CTL_SB_LLL; } else if (sb_ul == 'u') { - chspec_ch = LOWER_20_SB(ctl_ch); + chspec_ch = LOWER_20_SB(pri_ch); chspec_sb = WL_CHANSPEC_CTL_SB_LLU; } } /* if the bw is 20, center and sideband are trivial */ - else if (BW_LE20(chspec_bw)) { - chspec_ch = ctl_ch; + else if (chspec_bw == WL_CHANSPEC_BW_20) { + chspec_ch = pri_ch; chspec_sb = WL_CHANSPEC_CTL_SB_NONE; } /* if the bw is 40/80/160, not 80+80, a single method * can be used to to find the center and sideband */ else if (chspec_bw != WL_CHANSPEC_BW_8080) { - /* figure out ctl sideband based on ctl channel and bandwidth */ + /* figure out primary20 sideband based on primary20 channel and bandwidth */ const uint8 *center_ch = NULL; int num_ch = 0; int sb = -1; @@ -546,10 +603,10 @@ } for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); + sb = channel_to_sb(center_ch[i], pri_ch, bw); if (sb >= 0) { chspec_ch = center_ch[i]; - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + chspec_sb = (uint)(sb << WL_CHANSPEC_CTL_SB_SHIFT); break; } } @@ -579,16 +636,16 @@ /* figure out primary 20 MHz sideband */ /* is the primary channel contained in the 1st 80MHz channel? */ - sb = channel_to_sb(ch1, ctl_ch, bw); + sb = channel_to_sb(ch1, pri_ch, bw); if (sb < 0) { - /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */ + /* no match for primary channel 'pri_ch' in segment0 80MHz channel */ return 0; } - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; + chspec_sb = (uint)(sb << WL_CHANSPEC_CTL_SB_SHIFT); } - chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); + chspec = (chanspec_t)(chspec_ch | chspec_band | chspec_bw | chspec_sb); if (wf_chspec_malformed(chspec)) return 0; @@ -596,9 +653,18 @@ return chspec; } +/* given a chanspec string, convert to a chanspec. + * On error return 0 + */ +chanspec_t +wf_chspec_aton(const char *a) +{ + return wf_chspec_aton_ex(a, WL_CHANSPEC_BW_20); +} + /* * Verify the chanspec is using a legal set of parameters, i.e. that the - * chanspec specified a band, bw, ctl_sb and channel and that the + * chanspec specified a band, bw, pri_sb and channel and that the * combination could be legal given any set of circumstances. * RETURNS: TRUE is the chanspec is malformed, false if it looks good. */ @@ -608,10 +674,9 @@ uint chspec_bw = CHSPEC_BW(chanspec); uint chspec_ch = CHSPEC_CHANNEL(chanspec); - /* must be 2G or 5G band */ if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth */ - if (!BW_LE40(chspec_bw)) { + /* must be valid bandwidth and channel */ + if (!BW_LE40(chspec_bw) || (chspec_ch > CH_MAX_2G_CHANNEL)) { return TRUE; } } else if (CHSPEC_IS5G(chanspec)) { @@ -624,7 +689,29 @@ if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) return TRUE; - } else if (BW_LE160(chspec_bw)) { + } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || + chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { + + if (chspec_ch > MAXCHANNEL) { + return TRUE; + } + } else { + /* invalid bandwidth */ + return TRUE; + } + } else if (CHSPEC_IS6G(chanspec)) { + if (chspec_bw == WL_CHANSPEC_BW_8080) { + uint ch1_id, ch2_id; + + /* channel IDs in 80+80 must be in range */ + ch1_id = CHSPEC_CHAN1(chanspec); + ch2_id = CHSPEC_CHAN2(chanspec); + if (ch1_id >= WF_NUM_6G_80M_CHANS || ch2_id >= WF_NUM_6G_80M_CHANS) + return TRUE; + + } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || + chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { + if (chspec_ch > MAXCHANNEL) { return TRUE; } @@ -633,12 +720,13 @@ return TRUE; } } else { - /* must be 2G or 5G band */ + + /* must be 2G, 5G or 6G band */ return TRUE; } /* side band needs to be consistent with bandwidth */ - if (BW_LE20(chspec_bw)) { + if (chspec_bw == WL_CHANSPEC_BW_20) { if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) return TRUE; } else if (chspec_bw == WL_CHANSPEC_BW_40) { @@ -646,6 +734,9 @@ return TRUE; } else if (chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_8080) { + /* both 80MHz and 80+80MHz use 80MHz side bands. + * 80+80 SB info is relative to the primary 80MHz sub-band. + */ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) return TRUE; } @@ -670,7 +761,7 @@ if (CHSPEC_IS2G(chanspec)) { /* must be valid bandwidth and channel range */ - if (BW_LE20(chspec_bw)) { + if (chspec_bw == WL_CHANSPEC_BW_20) { if (chspec_ch >= 1 && chspec_ch <= 14) return TRUE; } else if (chspec_bw == WL_CHANSPEC_BW_40) { @@ -692,7 +783,7 @@ const uint8 *center_ch; uint num_ch, i; - if (BW_LE40(chspec_bw)) { + if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { center_ch = wf_5g_40m_chans; num_ch = WF_NUM_5G_40M_CHANS; } else if (chspec_bw == WL_CHANSPEC_BW_80) { @@ -707,7 +798,7 @@ } /* check for a valid center channel */ - if (BW_LE20(chspec_bw)) { + if (chspec_bw == WL_CHANSPEC_BW_20) { /* We don't have an array of legal 20MHz 5G channels, but they are * each side of the legal 40MHz channels. Check the chanspec * channel against either side of the 40MHz channels. @@ -749,12 +840,66 @@ } /* - * This function returns the channel number that control traffic is being sent on, for 20MHz - * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ - * sideband depending on the chanspec selected + * This function returns TRUE if both the chanspec can co-exist in PHY. + * Addition to primary20 channel, the function checks for side band for 2g 40 channels + */ +bool +wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2) +{ + bool same_primary; + + same_primary = (wf_chspec_primary20_chan(chspec1) == wf_chspec_primary20_chan(chspec2)); + + if (same_primary && CHSPEC_IS2G(chspec1)) { + if (CHSPEC_IS40(chspec1) && CHSPEC_IS40(chspec2)) { + return (CHSPEC_CTL_SB(chspec1) == CHSPEC_CTL_SB(chspec2)); + } + } + return same_primary; +} + +/** + * Create a 20MHz chanspec for the given band. + * + * This function returns a 20MHz chanspec in the given band. + * + * @param channel 20MHz channel number + * @param band a chanspec band (e.g. WL_CHANSPEC_BAND_2G) + * + * @return Returns a 20MHz chanspec, or IVNCHANSPEC in case of error. + */ +chanspec_t +wf_create_20MHz_chspec(uint channel, chanspec_band_t band) +{ + chanspec_t chspec; + + if (channel <= WL_CHANSPEC_CHAN_MASK && + (band == WL_CHANSPEC_BAND_2G || + band == WL_CHANSPEC_BAND_5G)) { + chspec = band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | channel; + if (!wf_chspec_valid(chspec)) { + chspec = INVCHANSPEC; + } + } else { + chspec = INVCHANSPEC; + } + + return chspec; +} + +/** + * Return the primary 20MHz channel. + * + * This function returns the channel number of the primary 20MHz channel. For + * 20MHz channels this is just the channel number. For 40MHz or wider channels + * it is the primary 20MHz channel specified by the chanspec. + * + * @param chspec input chanspec + * + * @return Returns the channel number of the primary 20MHz channel */ uint8 -wf_chspec_ctlchan(chanspec_t chspec) +wf_chspec_primary20_chan(chanspec_t chspec) { uint center_chan; uint bw_mhz; @@ -763,7 +908,7 @@ ASSERT(!wf_chspec_malformed(chspec)); /* Is there a sideband ? */ - if (CHSPEC_BW_LE20(chspec)) { + if (CHSPEC_IS20(chspec)) { return CHSPEC_CHANNEL(chspec); } else { sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; @@ -780,46 +925,46 @@ center_chan = wf_5g_80m_chans[chan_id]; } else { - bw_mhz = bw_chspec_to_mhz(chspec); + bw_mhz = wf_bw_chspec_to_mhz(chspec); center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; } - return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); + return (channel_to_primary20_chan(center_chan, bw_mhz, sb)); } } /* given a chanspec, return the bandwidth string */ -char * -wf_chspec_to_bw_str(chanspec_t chspec) +const char * +BCMRAMFN(wf_chspec_to_bw_str)(chanspec_t chspec) { - return (char *)wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; + return wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; } /* - * This function returns the chanspec of the control channel of a given chanspec + * Return the primary 20MHz chanspec of the given chanspec */ chanspec_t -wf_chspec_ctlchspec(chanspec_t chspec) +wf_chspec_primary20_chspec(chanspec_t chspec) { - chanspec_t ctl_chspec = chspec; - uint8 ctl_chan; + chanspec_t pri_chspec = chspec; + uint8 pri_chan; ASSERT(!wf_chspec_malformed(chspec)); /* Is there a sideband ? */ - if (!CHSPEC_BW_LE20(chspec)) { - ctl_chan = wf_chspec_ctlchan(chspec); - ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; - ctl_chspec |= CHSPEC_BAND(chspec); + if (!CHSPEC_IS20(chspec)) { + pri_chan = wf_chspec_primary20_chan(chspec); + pri_chspec = pri_chan | WL_CHANSPEC_BW_20; + pri_chspec |= CHSPEC_BAND(chspec); } - return ctl_chspec; + return pri_chspec; } -/* return chanspec given control channel and bandwidth +/* return chanspec given primary 20MHz channel and bandwidth * return 0 on error */ uint16 -wf_channel2chspec(uint ctl_ch, uint bw) +wf_channel2chspec(uint pri_ch, uint bw) { uint16 chspec; const uint8 *center_ch = NULL; @@ -827,7 +972,7 @@ int sb = -1; int i = 0; - chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); + chspec = ((pri_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); chspec |= bw; @@ -843,15 +988,15 @@ center_ch = wf_5g_160m_chans; num_ch = WF_NUM_5G_160M_CHANS; bw = 160; - } else if (BW_LE20(bw)) { - chspec |= ctl_ch; + } else if (bw == WL_CHANSPEC_BW_20) { + chspec |= pri_ch; return chspec; } else { return 0; } for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); + sb = channel_to_sb(center_ch[i], pri_ch, bw); if (sb >= 0) { chspec |= center_ch[i]; chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); @@ -868,9 +1013,9 @@ } /* - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. + * This function returns the chanspec for the primary 40MHz of an 80MHz or wider channel. + * The primary 20MHz channel of the returned 40MHz chanspec is the same as the primary 20MHz + * channel of the input chanspec. */ extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) { @@ -902,7 +1047,7 @@ } /* Create primary 40MHz chanspec */ - chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | + chspec40 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | sb | center_chan); } @@ -926,7 +1071,7 @@ * frequency is not a 2.4 GHz channel, or if the frequency is not and even * multiple of 5 MHz from the base frequency to the base plus 1 GHz. * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + * Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3 */ int wf_mhz2channel(uint freq, uint start_factor) @@ -952,7 +1097,7 @@ if ((freq < base) || (freq > base + 1000)) return -1; - offset = freq - base; + offset = (int)(freq - base); ch = offset / 5; /* check that frequency is a 5MHz multiple from the base */ @@ -980,7 +1125,7 @@ * the answer is rounded down to an integral MHz. * -1 is returned for an out of range channel. * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 + * Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3 */ int wf_channel2mhz(uint ch, uint start_factor) @@ -993,7 +1138,7 @@ else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) freq = 2484; else - freq = ch * 5 + start_factor / 2; + freq = (int)(ch * 5 + start_factor / 2); return freq; } @@ -1026,7 +1171,7 @@ for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); - if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { + if (primary_channel == wf_chspec_primary20_chan(chanspec_cur)) { chanspec = chanspec_cur; break; } @@ -1051,7 +1196,7 @@ * * Returns INVCHANSPEC in case of error. * - * Refer to IEEE802.11ac section 22.3.14 "Channelization". + * Refer to 802.11-2016 section 22.3.14 "Channelization". */ chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1) @@ -1078,7 +1223,7 @@ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ sb = channel_to_sb(chan1, primary_20mhz, 80); if (sb < 0) { - /* no match for ctl_ch to either 80MHz center channel */ + /* no match for pri_ch to either 80MHz center channel */ return INVCHANSPEC; } /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */ @@ -1086,7 +1231,7 @@ seg1 = chan0_id; } - chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) | + chanspec = (uint16)((seg0 << WL_CHANSPEC_CHAN1_SHIFT) | (seg1 << WL_CHANSPEC_CHAN2_SHIFT) | (sb << WL_CHANSPEC_CTL_SB_SHIFT) | WL_CHANSPEC_BW_8080 | @@ -1108,93 +1253,47 @@ } /* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec + * Returns the center channel of the primary 80 MHz sub-band of the provided chanspec */ - uint8 wf_chspec_primary80_channel(chanspec_t chanspec) { + chanspec_t primary80_chspec; uint8 primary80_chan; - if (CHSPEC_IS80(chanspec)) { - primary80_chan = CHSPEC_CHANNEL(chanspec); - } - else if (CHSPEC_IS8080(chanspec)) { - /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ - primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); - } - else if (CHSPEC_IS160(chanspec)) { - uint8 center_chan = CHSPEC_CHANNEL(chanspec); - uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + primary80_chspec = wf_chspec_primary80_chspec(chanspec); - /* based on the sb value primary 80 channel can be retrieved - * if sb is in range 0 to 3 the lower band is the 80Mhz primary band - */ - if (sb < 4) { - primary80_chan = center_chan - CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */ - else - { - primary80_chan = center_chan + CH_40MHZ_APART; - } + if (primary80_chspec == INVCHANSPEC) { + primary80_chan = INVCHANNEL; + } else { + primary80_chan = CHSPEC_CHANNEL(primary80_chspec); } - else { - /* for 20 and 40 Mhz */ - primary80_chan = -1; - } + return primary80_chan; } /* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40/80 Mhz chanspec + * Returns the center channel of the secondary 80 MHz sub-band of the provided chanspec */ uint8 wf_chspec_secondary80_channel(chanspec_t chanspec) { + chanspec_t secondary80_chspec; uint8 secondary80_chan; - if (CHSPEC_IS8080(chanspec)) { - secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); - } - else if (CHSPEC_IS160(chanspec)) { - uint8 center_chan = CHSPEC_CHANNEL(chanspec); - uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; + secondary80_chspec = wf_chspec_secondary80_chspec(chanspec); - /* based on the sb value secondary 80 channel can be retrieved - * if sb is in range 0 to 3 upper band is the secondary 80Mhz band - */ - if (sb < 4) { - secondary80_chan = center_chan + CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ - else - { - secondary80_chan = center_chan - CH_40MHZ_APART; - } + if (secondary80_chspec == INVCHANSPEC) { + secondary80_chan = INVCHANNEL; + } else { + secondary80_chan = CHSPEC_CHANNEL(secondary80_chspec); } - else { - /* for 20, 40, and 80 Mhz */ - secondary80_chan = -1; - } + return secondary80_chan; } /* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - * - * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived - * - * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec - * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec + * Returns the chanspec for the primary 80MHz sub-band of an 160MHz or 80+80 channel */ chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec) @@ -1204,18 +1303,18 @@ uint sb; ASSERT(!wf_chspec_malformed(chspec)); + if (CHSPEC_IS80(chspec)) { chspec80 = chspec; } else if (CHSPEC_IS8080(chspec)) { - - /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ - center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); - sb = CHSPEC_CTL_SB(chspec); + /* primary sub-band is stored in seg0 */ + center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); + /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); + chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); } else if (CHSPEC_IS160(chspec)) { center_chan = CHSPEC_CHANNEL(chspec); @@ -1230,14 +1329,88 @@ center_chan += CH_40MHZ_APART; sb -= WL_CHANSPEC_CTL_SB_ULL; } + /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); + chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); } else { chspec80 = INVCHANSPEC; } return chspec80; +} + +/* + * Returns the chanspec for the secondary 80MHz sub-band of an 160MHz or 80+80 channel + */ +chanspec_t +wf_chspec_secondary80_chspec(chanspec_t chspec) +{ + chanspec_t chspec80; + uint center_chan; + + ASSERT(!wf_chspec_malformed(chspec)); + + if (CHSPEC_IS8080(chspec)) { + /* secondary sub-band is stored in seg1 */ + center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec)); + + /* Create secondary 80MHz chanspec */ + chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | + WL_CHANSPEC_BW_80 | + WL_CHANSPEC_CTL_SB_LL | + center_chan); + } + else if (CHSPEC_IS160(chspec)) { + center_chan = CHSPEC_CHANNEL(chspec); + + if (CHSPEC_CTL_SB(chspec) < WL_CHANSPEC_CTL_SB_ULL) { + /* Primary 80MHz is on lower side */ + center_chan -= CH_40MHZ_APART; + } + else { + /* Primary 80MHz is on upper side */ + center_chan += CH_40MHZ_APART; + } + + /* Create secondary 80MHz chanspec */ + chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | + WL_CHANSPEC_BW_80 | + WL_CHANSPEC_CTL_SB_LL | + center_chan); + } + else { + chspec80 = INVCHANSPEC; + } + + return chspec80; +} + +/* + * For 160MHz or 80P80 chanspec, set ch[0]/ch[1] to be the low/high 80 Mhz channels + * + * For 20/40/80MHz chanspec, set ch[0] to be the center freq, and chan[1]=-1 + */ +void +wf_chspec_get_80p80_channels(chanspec_t chspec, uint8 *ch) +{ + + if (CHSPEC_IS8080(chspec)) { + ch[0] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); + ch[1] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec)); + } + else if (CHSPEC_IS160(chspec)) { + uint8 center_chan = CHSPEC_CHANNEL(chspec); + ch[0] = center_chan - CH_40MHZ_APART; + ch[1] = center_chan + CH_40MHZ_APART; + } + else { + /* for 20, 40, and 80 Mhz */ + ch[0] = CHSPEC_CHANNEL(chspec); + ch[1] = 0xFFu; + } + return; + } #ifdef WL11AC_80P80 @@ -1253,40 +1426,130 @@ } #endif /* WL11AC_80P80 */ -#ifdef WL_OLDPPR -/* given a chanspec and a string buffer, format the chanspec as a - * string, and return the original pointer a. - * Min buffer length must be CHANSPEC_STR_LEN. - * On error return NULL +/* This routine returns the chanspec for a given operating class and + * channel number */ -char * -wf_chspec_ntoa_old(chanspec_t chspec, char *buf) +chanspec_t +wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel) { - const char *band, *bw, *sb; - uint channel; - - band = ""; - bw = ""; - sb = ""; - channel = CHSPEC_CHANNEL_OLD(chspec); - /* check for non-default band spec */ - if ((CHSPEC_IS2G_OLD(chspec) && channel > CH_MAX_2G_CHANNEL) || - (CHSPEC_IS5G_OLD(chspec) && channel <= CH_MAX_2G_CHANNEL)) - band = (CHSPEC_IS2G_OLD(chspec)) ? "b" : "a"; - if (CHSPEC_IS40_OLD(chspec)) { - if (CHSPEC_SB_UPPER_OLD(chspec)) { - sb = "u"; - channel += CH_10MHZ_APART; - } else { - sb = "l"; - channel -= CH_10MHZ_APART; - } - } else if (CHSPEC_IS10_OLD(chspec)) { - bw = "n"; + chanspec_t chanspec = 0; + uint16 opclass_info = 0; + uint16 lookupindex = 0; + switch (opclass) { + case 115: + lookupindex = 1; + break; + case 124: + lookupindex = 3; + break; + case 125: + lookupindex = 5; + break; + case 81: + lookupindex = 12; + break; + case 116: + lookupindex = 22; + break; + case 119: + lookupindex = 23; + break; + case 126: + lookupindex = 25; + break; + case 83: + lookupindex = 32; + break; + case 84: + lookupindex = 33; + break; + default: + lookupindex = 12; } - /* Outputs a max of 6 chars including '\0' */ - snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb); - return (buf); + if (lookupindex < 33) { + opclass_info = opclass_data[lookupindex-1]; + } + else { + opclass_info = opclass_data[11]; + } + chanspec = opclass_info | (uint16)channel; + return chanspec; } -#endif /* WL_OLDPPR */ + +/* This routine returns the opclass for a given chanspec */ +int +wf_channel_create_opclass_frm_chspec(chanspec_t chspec) +{ + BCM_REFERENCE(chspec); + /* TODO: Implement this function ! */ + return 12; /* opclass 12 for basic 2G channels */ +} + +/* Populates array with all 20MHz side bands of a given chanspec_t in the following order: + * primary20, secondary20, two secondary40s, four secondary80s. + * 'chspec' is the chanspec of interest + * 'pext' must point to an uint8 array of long enough to hold all side bands of the given chspec + * + * Works with 20, 40, 80, 80p80 and 160MHz chspec + */ +void +wf_get_all_ext(chanspec_t chspec, uint8 *pext) +{ +#ifdef WL11N_20MHZONLY + GET_ALL_SB(chspec, pext); +#else /* !WL11N_20MHZONLY */ + chanspec_t t = (CHSPEC_IS160(chspec) || CHSPEC_IS8080(chspec)) ? /* if bw > 80MHz */ + wf_chspec_primary80_chspec(chspec) : (chspec); /* extract primary 80 */ + /* primary20 channel as first element */ + uint8 pri_ch = (pext)[0] = wf_chspec_primary20_chan(t); + if (CHSPEC_IS20(chspec)) return; /* nothing more to do since 20MHz chspec */ + /* 20MHz EXT */ + (pext)[1] = pri_ch + (uint8)(IS_CTL_IN_L20(t) ? CH_20MHZ_APART : -CH_20MHZ_APART); + if (CHSPEC_IS40(chspec)) return; /* nothing more to do since 40MHz chspec */ + /* center 40MHz EXT */ + t = wf_channel2chspec((uint)(pri_ch + (IS_CTL_IN_L40(chspec) ? + CH_40MHZ_APART : -CH_40MHZ_APART)), WL_CHANSPEC_BW_40); + GET_ALL_SB(t, &((pext)[2])); /* get the 20MHz side bands in 40MHz EXT */ + if (CHSPEC_IS80(chspec)) return; /* nothing more to do since 80MHz chspec */ + t = CH80MHZ_CHSPEC(wf_chspec_secondary80_channel(chspec), WL_CHANSPEC_CTL_SB_LLL); + /* get the 20MHz side bands in 80MHz EXT (secondary) */ + GET_ALL_SB(t, &((pext)[4])); +#endif /* !WL11N_20MHZONLY */ +} + +/* + * Given two chanspecs, returns true if they overlap. + * (Overlap: At least one 20MHz subband is common between the two chanspecs provided) + */ +bool wf_chspec_overlap(chanspec_t chspec0, chanspec_t chspec1) +{ + uint8 ch0, ch1; + + FOREACH_20_SB(chspec0, ch0) { + FOREACH_20_SB(chspec1, ch1) { + if (ABS(ch0 - ch1) < CH_20MHZ_APART) { + return TRUE; + } + } + } + + return FALSE; +} + +uint8 +channel_bw_to_width(chanspec_t chspec) +{ + uint8 channel_width; + + if (CHSPEC_IS80(chspec)) + channel_width = VHT_OP_CHAN_WIDTH_80; + else if (CHSPEC_IS160(chspec)) + channel_width = VHT_OP_CHAN_WIDTH_160; + else if (CHSPEC_IS8080(chspec)) + channel_width = VHT_OP_CHAN_WIDTH_80_80; + else + channel_width = VHT_OP_CHAN_WIDTH_20_40; + + return channel_width; +} -- Gitblit v1.6.2