wlan: linux regulatory changes
Properly separate out the regulatory changes when CONFIG_ENABLE_LINUX_REG
is defined and when it is not defined.
Change-Id: Ia01777a8b2e18a52b532e460a9ebcb1ab3196e50
CRs-Fixed: 538940
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 99d4368..25d7abc 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -172,6 +172,12 @@
#else
int wlan_hdd_linux_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
#endif
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+void wlan_hdd_crda_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+#else
+int wlan_hdd_crda_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+#endif
#endif
extern v_VOID_t hdd_connSetConnectionState( hdd_station_ctx_t *pHddStaCtx,
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 0cf6604..3842505 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -138,7 +138,11 @@
#define WAIT_TIME_TDLS_INITIATOR 600
/* Maximum time to get linux regulatory entry settings */
+#ifdef CONFIG_ENABLE_LINUX_REG
#define LINUX_REG_WAIT_TIME 300
+#else
+#define CRDA_WAIT_TIME 300
+#endif
/* Scan Req Timeout */
#define WLAN_WAIT_TIME_SCAN_REQ 100
@@ -1022,7 +1026,11 @@
struct completion mc_sus_event_var;
/* Completion variable for regulatory hint */
+#ifdef CONFIG_ENABLE_LINUX_REG
struct completion linux_reg_req;
+#else
+ struct completion driver_crda_req;
+#endif
v_BOOL_t isWlanSuspended;
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 73db6ad..aa64d3d 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -639,17 +639,22 @@
wiphy->mgmt_stypes = wlan_hdd_txrx_stypes;
+ wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+
+
/* This will disable updating of NL channels from passive to
* active if a beacon is received on passive channel. */
wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME
| WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
| WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
| WIPHY_FLAG_OFFCHAN_TX;
#endif
+
#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
if (pCfg->isFastTransitionEnabled
#ifdef FEATURE_WLAN_LFR
@@ -682,6 +687,8 @@
regulatory settings */
wiphy->reg_notifier = wlan_hdd_linux_reg_notifier;
+#else
+ wiphy->reg_notifier = wlan_hdd_crda_reg_notifier;
#endif
wiphy->max_scan_ssids = MAX_SCAN_SSID;
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 66d5fae..4a57141 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -6725,7 +6725,12 @@
init_completion(&pHddCtx->req_bmps_comp_var);
init_completion(&pHddCtx->scan_info.scan_req_completion_event);
init_completion(&pHddCtx->scan_info.abortscan_event_var);
+
+#ifdef CONFIG_ENABLE_LINUX_REG
init_completion(&pHddCtx->linux_reg_req);
+#else
+ init_completion(&pHddCtx->driver_crda_req);
+#endif
spin_lock_init(&pHddCtx->schedScan_lock);
@@ -6870,11 +6875,20 @@
goto err_wdclose;
}
+#ifdef CONFIG_ENABLE_LINUX_REG
+ /* registration of wiphy dev with cfg80211 */
+ if (0 > wlan_hdd_cfg80211_register(wiphy))
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: wiphy register failed", __func__);
+ goto err_clkvote;
+ }
+#endif
+
status = vos_open( &pVosContext, 0);
if ( !VOS_IS_STATUS_SUCCESS( status ))
{
hddLog(VOS_TRACE_LEVEL_FATAL, "%s: vos_open failed", __func__);
- goto err_clkvote;
+ goto err_wiphy_unregister;
}
pHddCtx->hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, pVosContext );
@@ -7015,6 +7029,8 @@
__func__);
goto err_vosstop;
}
+
+#ifndef CONFIG_ENABLE_LINUX_REG
wlan_hdd_cfg80211_update_reg_info( wiphy );
/* registration of wiphy dev with cfg80211 */
@@ -7023,6 +7039,7 @@
hddLog(VOS_TRACE_LEVEL_ERROR,"%s: wiphy register failed", __func__);
goto err_vosstop;
}
+#endif
if (VOS_STA_SAP_MODE == hdd_get_conparam())
{
@@ -7267,21 +7284,31 @@
err_close_adapter:
hdd_close_all_adapters( pHddCtx );
+
+#ifndef CONFIG_ENABLE_LINUX_REG
wiphy_unregister(wiphy) ;
+#endif
err_vosstop:
vos_stop(pVosContext);
-err_vosclose:
+err_vosclose:
status = vos_sched_close( pVosContext );
if (!VOS_IS_STATUS_SUCCESS(status)) {
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
"%s: Failed to close VOSS Scheduler", __func__);
VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ) );
}
- vos_close(pVosContext );
+ vos_close(pVosContext );
+
+err_wiphy_unregister:
+
+#ifdef CONFIG_ENABLE_LINUX_REG
+ wiphy_unregister(wiphy);
err_clkvote:
+#endif
+
vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
err_wdclose:
diff --git a/CORE/VOSS/src/vos_nvitem.c b/CORE/VOSS/src/vos_nvitem.c
index 1615e5e..728d0b1 100644
--- a/CORE/VOSS/src/vos_nvitem.c
+++ b/CORE/VOSS/src/vos_nvitem.c
@@ -67,18 +67,22 @@
#include "wlan_hdd_main.h"
#include <net/cfg80211.h>
-static v_REGDOMAIN_t cur_reg_domain = REGDOMAIN_COUNT;
+
#ifdef CONFIG_ENABLE_LINUX_REG
-static v_BOOL_t kernel_reg_request_made = VOS_FALSE;
-static v_BOOL_t driver_callback_called = VOS_FALSE;
+
+static v_REGDOMAIN_t cur_reg_domain = REGDOMAIN_COUNT;
static char linux_reg_cc[2] = {0, 0};
static v_BOOL_t linux_regulatory_init = VOS_FALSE;
static v_REGDOMAIN_t temp_reg_domain = REGDOMAIN_COUNT;
-#else
-static v_BOOL_t driver_regulatory_init = VOS_FALSE;
-static char driver_reg_cc[2] = {0, 0};
+
#endif
+static char crda_alpha2[2] = {0, 0}; /* country code from initial crda req */
+static char run_time_alpha2[2] = {0, 0}; /* country code from none-default country req */
+static v_BOOL_t crda_regulatory_entry_valid = VOS_FALSE;
+static v_BOOL_t crda_regulatory_run_time_entry_valid = VOS_FALSE;
+
+
/*----------------------------------------------------------------------------
* Preprocessor Definitions and Constants
@@ -117,6 +121,9 @@
/*----------------------------------------------------------------------------
* Static Variable Definitions
* -------------------------------------------------------------------------*/
+// cache of country info table;
+// this is re-initialized from data on binary file
+// loaded on driver initialization if available
#ifdef CONFIG_ENABLE_LINUX_REG
@@ -534,6 +541,7 @@
#endif
+
typedef struct nvEFSTable_s
{
v_U32_t nvValidityBitmap;
@@ -1081,7 +1089,6 @@
sufficient
\sa
-------------------------------------------------------------------------*/
-
VOS_STATUS vos_nv_getSupportedCountryCode( v_BYTE_t *pBuffer, v_SIZE_t *pBufferSize,
v_SIZE_t paddingSize )
{
@@ -1092,7 +1099,7 @@
if ( NULL == pBuffer || providedBufferSize < *pBufferSize )
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("Insufficient memory for country code list"));
+ ("Insufficient memory for country code list\n"));
return VOS_STATUS_E_NOMEM;
}
for (i = 0; i < countryInfoTable.countryCount; i++)
@@ -1264,7 +1271,7 @@
gnvEFSTable->nvValidityBitmap = newNvValidityBitmap;
status = wlan_write_to_efs((v_U8_t*)gnvEFSTable,sizeof(nvEFSTable_t));
if (! VOS_IS_STATUS_SUCCESS(status)) {
- VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, ("vos_nv_write_to_efs failed!!!"));
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, ("vos_nv_write_to_efs failed!!!\r\n"));
status = VOS_STATUS_E_FAULT;
}
}
@@ -1325,7 +1332,7 @@
v_SIZE_t itemSize;
v_BOOL_t itemIsValid = VOS_TRUE;
- /* sanity check */
+ // sanity check
if (VNV_TYPE_COUNT <= type)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
@@ -1335,13 +1342,13 @@
if (NULL == outputVoidBuffer)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("Buffer provided is NULL") );
+ ("Buffer provided is NULL\r\n") );
return VOS_STATUS_E_FAULT;
}
if (0 == bufferSize)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("NV type=%d is invalid"), type );
+ ("NV type=%d is invalid\r\n"), type );
return VOS_STATUS_E_INVAL;
}
// check if the NV item has valid data
@@ -1349,7 +1356,7 @@
if (!itemIsValid)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- "NV type=%d does not have valid data", type );
+ "NV type=%d does not have valid data\r\n", type );
return VOS_STATUS_E_EMPTY;
}
switch(type)
@@ -1358,7 +1365,7 @@
itemSize = sizeof(gnvEFSTable->halnv.fields);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1370,7 +1377,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.pwrOptimum);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1382,7 +1389,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.regDomains);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1394,7 +1401,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.defaultCountryTable);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1406,7 +1413,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.plutCharacterized);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1418,7 +1425,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.plutPdadcOffset);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1433,7 +1440,7 @@
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1448,7 +1455,7 @@
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1463,7 +1470,7 @@
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1475,7 +1482,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.antennaPathLoss);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1487,7 +1494,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.pktTypePwrLimits);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1499,7 +1506,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.ofdmCmdPwrOffset);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1511,7 +1518,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.txbbFilterMode);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1525,7 +1532,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.pwrOptimum_virtualRate);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1560,7 +1567,7 @@
VOS_STATUS status = VOS_STATUS_SUCCESS;
v_SIZE_t itemSize;
- /* sanity check */
+ // sanity check
if (VNV_TYPE_COUNT <= type)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
@@ -1570,13 +1577,13 @@
if (NULL == inputVoidBuffer)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("Buffer provided is NULL") );
+ ("Buffer provided is NULL\r\n") );
return VOS_STATUS_E_FAULT;
}
if (0 == bufferSize)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("NV type=%d is invalid"), type );
+ ("NV type=%d is invalid\r\n"), type );
return VOS_STATUS_E_INVAL;
}
switch(type)
@@ -1585,7 +1592,7 @@
itemSize = sizeof(gnvEFSTable->halnv.fields);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1597,7 +1604,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.pwrOptimum);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1609,7 +1616,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.regDomains);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1621,7 +1628,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.defaultCountryTable);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1633,7 +1640,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.plutCharacterized);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1645,7 +1652,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.plutPdadcOffset);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"), type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1660,7 +1667,7 @@
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1675,7 +1682,7 @@
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1690,7 +1697,7 @@
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1702,7 +1709,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.antennaPathLoss);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1715,7 +1722,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.pktTypePwrLimits);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1728,7 +1735,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.ofdmCmdPwrOffset);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1741,7 +1748,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.txbbFilterMode);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1755,7 +1762,7 @@
itemSize = sizeof(gnvEFSTable->halnv.tables.pwrOptimum_virtualRate);
if(bufferSize != itemSize) {
VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("type = %d buffer size=%d is less than data size=%d"),type, bufferSize,
+ ("type = %d buffer size=%d is less than data size=%d\r\n"),type, bufferSize,
itemSize);
status = VOS_STATUS_E_INVAL;
}
@@ -1772,13 +1779,13 @@
// set NV item to have valid data
status = vos_nv_setValidity( type, VOS_TRUE );
if (! VOS_IS_STATUS_SUCCESS(status)) {
- VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, ("vos_nv_setValidity failed!!!"));
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, ("vos_nv_setValidity failed!!!\r\n"));
status = VOS_STATUS_E_FAULT;
}
status = wlan_write_to_efs((v_U8_t*)gnvEFSTable,sizeof(nvEFSTable_t));
if (! VOS_IS_STATUS_SUCCESS(status)) {
- VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, ("vos_nv_write_to_efs failed!!!"));
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, ("vos_nv_write_to_efs failed!!!\r\n"));
status = VOS_STATUS_E_FAULT;
}
}
@@ -1996,37 +2003,6 @@
}
/**------------------------------------------------------------------------
- \brief vos_nv_setRegDomain -
- \param clientCtxt - Client Context, Not used for PRIMA
- regId - Regulatory Domain ID
- \return status set REG domain operation
- \sa
- -------------------------------------------------------------------------*/
-VOS_STATUS vos_nv_setRegDomain(void * clientCtxt, v_REGDOMAIN_t regId)
-{
- v_CONTEXT_t pVosContext = NULL;
- hdd_context_t *pHddCtx = NULL;
-
- /* Client Context Argumant not used for PRIMA */
- if (regId >= REGDOMAIN_COUNT)
- {
- VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- "VOS set reg domain, invalid REG domain ID %d", regId);
- return VOS_STATUS_E_INVAL;
- }
-
- pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
- if (NULL != pVosContext)
- pHddCtx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext);
- else
- return VOS_STATUS_E_EXISTS;
- /* Set correct channel information based on REG Domain */
- regChannels = pnvEFSTable->halnv.tables.regDomains[regId].channels;
-
- return VOS_STATUS_SUCCESS;
-}
-
-/**------------------------------------------------------------------------
\brief vos_nv_getChannelEnabledState -
\param rfChannel - input channel enum to know evabled state
\return eNVChannelEnabledType enabled state for channel
@@ -2063,476 +2039,523 @@
}
/******************************************************************
- Add driver/linux regulatory support
+ Add CRDA regulatory support
*******************************************************************/
-#ifdef CONFIG_ENABLE_LINUX_REG
-
-/* Handling routines for the conversion from regd rules (start/end freq) to channel index
- start freq + 10000 = center freq of the 20MHz start channel
- end freq - 10000 = center freq of the 20MHz end channel
- start freq + 20000 = center freq of the 40MHz start channel
- end freq - 20000 = center freq of the 40MHz end channel
-*/
-static int bw20_start_freq_to_channel_index(u32 freq_khz)
-{
- int i;
- u32 center_freq = freq_khz + 10000;
-
- /* Has to compare from low freq to high freq */
-
- /* RF_SUBBAND_2_4_GHZ */
- for (i = RF_CHAN_1; i <= RF_CHAN_14; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_4_9_GHZ, Ch 240, 244, 248, 252, 208, 212, 216 */
- for (i = RF_CHAN_240; i <= RF_CHAN_216; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_LOW_GHZ */
- for (i = RF_CHAN_36; i <= RF_CHAN_64; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_MID_GHZ */
- for (i = RF_CHAN_100; i <= RF_CHAN_140; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_HIGH_GHZ */
- for (i = RF_CHAN_149; i <= RF_CHAN_165; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- return -1;
-}
-
-static int bw20_end_freq_to_channel_index(u32 freq_khz)
-{
- int i;
- u32 center_freq = freq_khz - 10000;
-
- /* Has to compare from high freq to low freq */
-
- /* RF_SUBBAND_5_HIGH_GHZ */
- for (i = RF_CHAN_165; i >= RF_CHAN_149; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_MID_GHZ */
- for (i = RF_CHAN_140; i >= RF_CHAN_100; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_LOW_GHZ */
- for (i = RF_CHAN_64; i >= RF_CHAN_36; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_4_9_GHZ, Ch 216, 212, 208, 252, 248, 244, 240 */
- for (i = RF_CHAN_216;i >= RF_CHAN_240; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_2_4_GHZ */
- for (i = RF_CHAN_14; i >= RF_CHAN_1; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- return -1;
-}
-
-static int bw40_start_freq_to_channel_index(u32 freq_khz)
-{
- int i;
- u32 center_freq = freq_khz + 20000;
-
- /* Has to compare from low freq to high freq */
-
- /* RF_SUBBAND_2_4_GHZ */
- for (i = RF_CHAN_BOND_3; i <= RF_CHAN_BOND_11; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_4_9_GHZ, Ch 242, 246, 250, 210, 214 */
- for (i = RF_CHAN_BOND_242; i <= RF_CHAN_BOND_214; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_LOW_GHZ */
- for (i = RF_CHAN_BOND_38; i<= RF_CHAN_BOND_62; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_MID_GHZ */
- for (i = RF_CHAN_BOND_102; i <= RF_CHAN_BOND_138; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_HIGH_GHZ */
- for (i = RF_CHAN_BOND_151;i <= RF_CHAN_BOND_163; i++)
- if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- return -1;
-}
-
-static int bw40_end_freq_to_channel_index(u32 freq_khz)
-{
- int i;
- u32 center_freq = freq_khz - 20000;
-
- /* Has to compare from high freq to low freq */
-
- /* RF_SUBBAND_5_HIGH_GHZ */
- for (i = RF_CHAN_BOND_163; i >= RF_CHAN_BOND_151; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_MID_GHZ */
- for (i = RF_CHAN_BOND_138; i >= RF_CHAN_BOND_102; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_5_LOW_GHZ */
- for (i = RF_CHAN_BOND_62; i >= RF_CHAN_BOND_38; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_4_9_GHZ, Ch 214, 210, 250, 246, 242 */
- for (i = RF_CHAN_BOND_214; i >= RF_CHAN_BOND_242; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- /* RF_SUBBAND_2_4_GHZ */
- for (i = RF_CHAN_BOND_11; i >= RF_CHAN_BOND_3; i--)
- if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
- return i;
-
- return -1;
-}
-
-static v_BOOL_t channel_in_capable_band(int j, v_U8_t nBandCapability)
-{
- switch (nBandCapability)
- {
- case eCSR_BAND_ALL:
- return VOS_TRUE;
-
- case eCSR_BAND_24:
- if (j >= RF_CHAN_1 && j <= RF_CHAN_14)
- return VOS_TRUE;
- if (j >= RF_CHAN_BOND_3 && j <= RF_CHAN_BOND_11)
- return VOS_TRUE; /* 2.4G 40MHz channel */
- break;
-
- case eCSR_BAND_5G:
- if (j >= RF_CHAN_240 && j <= RF_CHAN_165)
- return VOS_TRUE;
- if (j >= RF_CHAN_BOND_242 && j <= RF_CHAN_BOND_163)
- return VOS_TRUE; /* 5G 40MHz channel */
- break;
- default:
- break;
- }
- return VOS_FALSE;
-}
-
-
-/* create_linux_regulatory_entry should */
-static void create_linux_regulatory_entry_driver(struct wiphy *wiphy,
- struct regulatory_request *request,
- v_U8_t nBandCapability,
- v_REGDOMAIN_t domain_id)
-{
- int i, j, n;
- int bw20_start_channel_index, bw20_end_channel_index;
- int bw40_start_channel_index, bw40_end_channel_index;
-
- if (NULL == wiphy->regd)
- return;
-
- for (n = 0; n < NUM_RF_CHANNELS; n++)
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].enabled =
- NV_CHANNEL_DISABLE;
-
- for (i = 0; i < wiphy->regd->n_reg_rules; i++)
- {
-
- wiphy_dbg(wiphy, "info: rule %d --------------------------------------------\n", i);
-
- bw20_start_channel_index =
- bw20_start_freq_to_channel_index(
- wiphy->regd->reg_rules[i].freq_range.start_freq_khz);
-
- bw20_end_channel_index =
- bw20_end_freq_to_channel_index(
- wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
-
- if (bw20_start_channel_index == -1 || bw20_end_channel_index == -1)
- {
- wiphy_dbg(wiphy, "error: freq not supported, start freq (KHz) %d end freq %d\n",
- wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
- wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
- continue; /* skip this rule, but continue to next rule */
- }
-
- wiphy_dbg(wiphy, "20MHz start freq (KHz) %d end freq %d start ch index %d end ch index %d\n",
- wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
- wiphy->regd->reg_rules[i].freq_range.end_freq_khz,
- bw20_start_channel_index, bw20_end_channel_index);
-
- for (j = bw20_start_channel_index; j <= bw20_end_channel_index; j++)
- {
-
- if (channel_in_capable_band(j, nBandCapability) == VOS_FALSE)
- {
- wiphy_dbg(wiphy, "info: CH %d is not in capable band\n",
- rfChannels[j].channelNum);
- continue; /* skip this channel, continue to next */
- }
-
- if ((wiphy->regd->reg_rules[i].flags & IEEE80211_CHAN_PASSIVE_SCAN) ||
- (wiphy->regd->reg_rules[i].flags & IEEE80211_CHAN_RADAR))
- {
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_DFS;
- wiphy_dbg(wiphy, "info: CH %d is DFS, max EIRP (mBm) is %d\n", rfChannels[j].channelNum,
- wiphy->regd->reg_rules[i].power_rule.max_eirp);
- }
- else
- {
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_ENABLE;
- wiphy_dbg(wiphy, "info: CH %d is enabled, no DFS, max EIRP (mBm) is %d\n", rfChannels[j].channelNum,
- wiphy->regd->reg_rules[i].power_rule.max_eirp);
- }
-
- /* max_eirp is in mBm (= 100 * dBm) unit */
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].pwrLimit =
- (tANI_S8) ((wiphy->regd->reg_rules[i].power_rule.max_eirp)/100);
- }
-
- /* ignore max_antenna_gain typical is 3dBi, nv.bin antennaGain is
- real gain which should be provided by the real design */
- if (wiphy->regd->reg_rules[i].freq_range.max_bandwidth_khz >= 40000)
- {
-
- wiphy_dbg(wiphy, "info: 40MHz (channel bonding) is allowed\n");
- bw40_start_channel_index =
- bw40_start_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.start_freq_khz);
- bw40_end_channel_index =
- bw40_end_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
-
- if (bw40_start_channel_index == -1 || bw40_end_channel_index == -1)
- {
- wiphy_dbg(wiphy, "error: req not supported, start_freq_khz %d end_freq_khz %d\n",
- wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
- wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
- continue; /* skip this rull, but continue to next rule */
- }
-
- wiphy_dbg(wiphy, "40MHz start freq (KHz) %d end freq %d start ch index %d end ch index %d\n",
- wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
- wiphy->regd->reg_rules[i].freq_range.end_freq_khz,
- bw40_start_channel_index, bw40_end_channel_index);
-
- for (j = bw40_start_channel_index; j <= bw40_end_channel_index; j++)
- {
- if (channel_in_capable_band(j, nBandCapability) == VOS_FALSE)
- continue; /* skip this channel, continue to next */
-
- if ((wiphy->regd->reg_rules[i].flags & IEEE80211_CHAN_PASSIVE_SCAN) ||
- (wiphy->regd->reg_rules[i].flags & IEEE80211_CHAN_RADAR))
- {
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_DFS;
- wiphy_dbg(wiphy, "info: 40MHz centered on CH %d is DFS\n", rfChannels[j].channelNum);
- }
- else
- {
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_ENABLE;
- wiphy_dbg(wiphy, "info: 40MHz centered on CH %d is enabled, no DFS\n", rfChannels[j].channelNum);
- }
-
- /* set 40MHz channel power as half (- 3 dB) of 20MHz */
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].pwrLimit =
- (tANI_S8) (((wiphy->regd->reg_rules[i].power_rule.max_eirp)/100)-3);
- }
- }
- }
-
-}
-
-/*
- note: these functions may get used at a later point in time
-
static int bw20_ch_index_to_bw40_ch_index(int k)
{
int m = -1;
-
if (k >= RF_CHAN_1 && k <= RF_CHAN_14)
{
- m = k - RF_CHAN_1 + RF_CHAN_BOND_3 ;
- if (m > RF_CHAN_BOND_11)
- m = RF_CHAN_BOND_11;
+ m = k - RF_CHAN_1 + RF_CHAN_BOND_3 ;
+ if (m > RF_CHAN_BOND_11)
+ m = RF_CHAN_BOND_11;
}
else if (k >= RF_CHAN_240 && k <= RF_CHAN_216)
{
- m = k - RF_CHAN_240 + RF_CHAN_BOND_242 ;
- if (m > RF_CHAN_BOND_214)
- m = RF_CHAN_BOND_214;
+ m = k - RF_CHAN_240 + RF_CHAN_BOND_242 ;
+ if (m > RF_CHAN_BOND_214)
+ m = RF_CHAN_BOND_214;
}
else if (k >= RF_CHAN_36 && k <= RF_CHAN_64)
{
- m = k - RF_CHAN_36 + RF_CHAN_BOND_38;
- if (m > RF_CHAN_BOND_62)
- m = RF_CHAN_BOND_62;
+ m = k - RF_CHAN_36 + RF_CHAN_BOND_38;
+ if (m > RF_CHAN_BOND_62)
+ m = RF_CHAN_BOND_62;
}
else if (k >= RF_CHAN_100 && k <= RF_CHAN_140)
{
- m = k - RF_CHAN_100 + RF_CHAN_BOND_102;
- if (m > RF_CHAN_BOND_138)
- m = RF_CHAN_BOND_138;
+ m = k - RF_CHAN_100 + RF_CHAN_BOND_102;
+ if (m > RF_CHAN_BOND_138)
+ m = RF_CHAN_BOND_138;
}
else if (k >= RF_CHAN_149 && k <= RF_CHAN_165)
{
- m = k - RF_CHAN_149 + RF_CHAN_BOND_151;
- if (m > RF_CHAN_BOND_163)
- m = RF_CHAN_BOND_163;
+ m = k - RF_CHAN_149 + RF_CHAN_BOND_151;
+ if (m > RF_CHAN_BOND_163)
+ m = RF_CHAN_BOND_163;
}
-
- return m;
+return m;
}
-
-static int create_linux_regulatory_entry_other(struct wiphy *wiphy,
- struct regulatory_request *request,
- v_U8_t nBandCapability,
- v_REGDOMAIN_t domain_id)
+void crda_regulatory_entry_default(v_U8_t *countryCode, int domain_id)
{
- int i, j, m;
- int k = 0, n = 0;
+ int k;
+ pr_info("Country %c%c domain_id %d\n enable ch 1 - 11.\n",
+ countryCode[0], countryCode[1], domain_id);
+ for (k = RF_CHAN_1; k <= RF_CHAN_11; k++) {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
+ NV_CHANNEL_ENABLE;
+ /* Max Tx Power 20dBm */
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].pwrLimit = 20;
+ }
+ /* enable ch 12 to ch 14 passive scan */
+ pr_info(" enable ch 12 - 14 to scan passively by setting DFS flag.\n");
+ for (k = RF_CHAN_12; k <= MAX_2_4GHZ_CHANNEL; k++) {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
+ NV_CHANNEL_DFS;
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].pwrLimit = 0;
+ }
+ pr_info(" enable 5GHz to scan passively by setting DFS flag.\n");
+ for (k = MIN_5GHZ_CHANNEL; k <= MAX_5GHZ_CHANNEL; k++) {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
+ NV_CHANNEL_DFS;
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].pwrLimit = 0;
+ }
+#ifdef PASSIVE_SCAN_4_9GHZ
+ pr_info(" enable 4.9 GHz to scan passively by setting DFS flag.\n");
+ for (k = RF_CHAN_240; k <= RF_CHAN_216; k++) {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
+ NV_CHANNEL_DFS;
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].pwrLimit = 0;
+ }
+#endif
+ if (domain_id == NUM_REG_DOMAINS-1)
+ { /* init time */
+ crda_alpha2[0] = countryCode[0];
+ crda_alpha2[1] = countryCode[1];
+ crda_regulatory_entry_valid = VOS_TRUE;
+ pnvEFSTable->halnv.tables.defaultCountryTable.countryCode[0] = countryCode[0];
+ pnvEFSTable->halnv.tables.defaultCountryTable.countryCode[1] = countryCode[1];
+ pnvEFSTable->halnv.tables.defaultCountryTable.countryCode[2] = 'I';
+ pnvEFSTable->halnv.tables.defaultCountryTable.regDomain = NUM_REG_DOMAINS-1;
+ }
+ if (domain_id == NUM_REG_DOMAINS-2)
+ { /* none-default country */
+ run_time_alpha2[0] = countryCode[0];
+ run_time_alpha2[1] = countryCode[1];
+ crda_regulatory_run_time_entry_valid = VOS_TRUE;
+ }
+}
- if (pnvEFSTable == NULL)
- {
- pr_info("error: pnvEFSTable is NULL, probably not parsed nv.bin yet\n");
- return -1;
- }
+static int crda_regulatory_entry_post_processing(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ v_U8_t nBandCapability,
+ int domain_id)
+{
+ if (request->alpha2[0] == '0' && request->alpha2[1] == '0') {
+ pr_info("Country 00 special handling to enable passive scan.\n");
+ crda_regulatory_entry_default(request->alpha2, domain_id);
+ }
+ return 0;
+}
- //20MHz channels
+/* create_crda_regulatory_entry should be called from user command or 11d country IE */
+static int create_crda_regulatory_entry(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ v_U8_t nBandCapability)
+{
+ int i, j, m;
+ int k = 0, n = 0;
+
+ if (run_time_alpha2[0]==request->alpha2[0] &&
+ run_time_alpha2[1]==request->alpha2[1] &&
+ crda_regulatory_run_time_entry_valid == VOS_TRUE)
+ return 0; /* already created */
+
+ /* 20MHz channels */
if (nBandCapability == eCSR_BAND_24)
pr_info("BandCapability is set to 2G only.\n");
-
- for (i = 0, m = 0; i < IEEE80211_NUM_BANDS; i++)
+ for (i=0,m=0;i<IEEE80211_NUM_BANDS;i++)
{
if (i == IEEE80211_BAND_2GHZ && nBandCapability == eCSR_BAND_5G) // 5G only
continue;
else if (i == IEEE80211_BAND_5GHZ && nBandCapability == eCSR_BAND_24) // 2G only
continue;
-
if (wiphy->bands[i] == NULL)
{
pr_info("error: wiphy->bands[i] is NULL, i = %d\n", i);
return -1;
}
-
- //internal channels[] is one continous array for both 2G and 5G bands
- //m is internal starting channel index for each band
+ // internal channels[] is one continous array for both 2G and 5G bands
+ // m is internal starting channel index for each band
if (i == 0)
m = 0;
else
m = wiphy->bands[i-1]->n_channels + m;
-
- for (j = 0; j < wiphy->bands[i]->n_channels; j++)
+ for (j=0;j<wiphy->bands[i]->n_channels;j++)
{
- //k = (m + j) is internal current channel index for 20MHz channel
- //n is internal channel index for corresponding 40MHz channel
-
+ // k = (m + j) is internal current channel index for 20MHz channel
+ // n is internal channel index for corresponding 40MHz channel
k = m + j;
n = bw20_ch_index_to_bw40_ch_index(k);
-
if (n == -1)
- return -1;
-
+ return -1;
if (wiphy->bands[i]->channels[j].flags & IEEE80211_CHAN_DISABLED)
{
-
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
- NV_CHANNEL_DISABLE;
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].enabled =
- NV_CHANNEL_DISABLE;
+ if (pnvEFSTable == NULL)
+ {
+ pr_info("error: pnvEFSTable is NULL, probably not parsed nv.bin yet\n");
+ return -1;
+ }
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[k].enabled =
+ NV_CHANNEL_DISABLE;
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[n].enabled =
+ NV_CHANNEL_DISABLE;
+ //pr_info("CH %d disabled, no bonding centered on CH %d.\n", rfChannels[k].channelNum,
+ // rfChannels[n].channelNum);
}
-
else if (wiphy->bands[i]->channels[j].flags & IEEE80211_CHAN_RADAR)
{
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
- NV_CHANNEL_DFS;
-
- // max_power is in mBm = 100 * dBm
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].pwrLimit =
- (tANI_S8) ((wiphy->bands[i]->channels[j].max_power)/100);
- if ((wiphy->bands[i]->channels[j].flags & IEEE80211_CHAN_NO_HT40) == 0)
- {
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].enabled =
- NV_CHANNEL_DFS;
- // 40MHz channel power is half of 20MHz (-3dB) ??
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].pwrLimit =
- (tANI_S8) (((wiphy->bands[i]->channels[j].max_power)/100)-3);
- }
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[k].enabled =
+ NV_CHANNEL_DFS;
+ // max_power is in mBm = 100 * dBm
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[k].pwrLimit =
+ (tANI_S8) ((wiphy->bands[i]->channels[j].max_power)/100);
+ if ((wiphy->bands[i]->channels[j].flags & IEEE80211_CHAN_NO_HT40) == 0)
+ {
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[n].enabled =
+ NV_CHANNEL_DFS;
+ // 40MHz channel power is half of 20MHz (-3dB) ??
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[n].pwrLimit =
+ (tANI_S8) (((wiphy->bands[i]->channels[j].max_power)/100)-3);
+ }
}
-
else // Enable is only last flag we support
{
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].enabled =
- NV_CHANNEL_ENABLE;
-
- // max_power is in dBm
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[k].pwrLimit =
- (tANI_S8) ((wiphy->bands[i]->channels[j].max_power)/100);
- if ((wiphy->bands[i]->channels[j].flags & IEEE80211_CHAN_NO_HT40) == 0)
- {
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].enabled =
- NV_CHANNEL_ENABLE;
-
- // 40MHz channel power is half of 20MHz (-3dB) ??
- pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].pwrLimit =
- (tANI_S8) (((wiphy->bands[i]->channels[j].max_power)/100)-3);
- }
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[k].enabled =
+ NV_CHANNEL_ENABLE;
+ // max_power is in dBm
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[k].pwrLimit =
+ (tANI_S8) ((wiphy->bands[i]->channels[j].max_power)/100);
+ if ((wiphy->bands[i]->channels[j].flags & IEEE80211_CHAN_NO_HT40) == 0)
+ {
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[n].enabled =
+ NV_CHANNEL_ENABLE;
+ // 40MHz channel power is half of 20MHz (-3dB) ??
+ pnvEFSTable->halnv.tables.regDomains[NUM_REG_DOMAINS-2].channels[n].pwrLimit =
+ (tANI_S8) (((wiphy->bands[i]->channels[j].max_power)/100)-3);
+ }
}
-
- // ignore max_antenna_gain typical is 3dBi, nv.bin antennaGain is
- // real gain which should be provided by the real design
+ /* ignore CRDA max_antenna_gain typical is 3dBi, nv.bin antennaGain is
+ real gain which should be provided by the real design */
}
}
-
if (k == 0)
return -1;
-
- return 0;
+ run_time_alpha2[0] = request->alpha2[0];
+ run_time_alpha2[1] = request->alpha2[1];
+ crda_regulatory_run_time_entry_valid = VOS_TRUE;
+ crda_regulatory_entry_post_processing(wiphy, request, nBandCapability, NUM_REG_DOMAINS-2);
+return 0;
+}
+v_BOOL_t is_crda_regulatory_entry_valid(void)
+{
+return crda_regulatory_entry_valid;
}
+/* Handling routines for the conversion from regd rules (start/end freq) to channel index
+start freq + 10000 = center freq of the 20MHz start channel
+end freq - 10000 = center freq of the 20MHz end channel
+start freq + 20000 = center freq of the 40MHz start channel
+end freq - 20000 = center freq of the 40MHz end channel
*/
-/**------------------------------------------------------------------------
- \brief vos_nv_getRegDomainFromCountryCode() - get the regulatory domain of
- a country given its country code
- The \a vos_nv_getRegDomainFromCountryCode() returns the regulatory domain of
- a country given its country code. This is done from reading a cached
- copy of the binary file.
- \param pRegDomain - pointer to regulatory domain
- \param countryCode - country code
- \return VOS_STATUS_SUCCESS - regulatory domain is found for the given country
- VOS_STATUS_E_FAULT - invalid pointer error
- VOS_STATUS_E_EMPTY - country code table is empty
- VOS_STATUS_E_EXISTS - given country code does not exist in table
- \sa
- -------------------------------------------------------------------------*/
-VOS_STATUS vos_nv_getRegDomainFromCountryCode( v_REGDOMAIN_t *pRegDomain,
- const v_COUNTRYCODE_t countryCode )
+static int bw20_start_freq_to_channel_index(u32 freq_khz)
{
+int i;
+u32 center_freq = freq_khz + 10000;
+ //Has to compare from low freq to high freq
+ //RF_SUBBAND_2_4_GHZ
+ for (i=RF_CHAN_1;i<=RF_CHAN_14;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_4_9_GHZ, Ch 240, 244, 248, 252, 208, 212, 216
+ for (i=RF_CHAN_240;i<=RF_CHAN_216;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_LOW_GHZ
+ for (i=RF_CHAN_36;i<=RF_CHAN_64;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_MID_GHZ
+ for (i=RF_CHAN_100;i<=RF_CHAN_140;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_HIGH_GHZ
+ for (i=RF_CHAN_149;i<=RF_CHAN_165;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+return -1;
+}
+
+static int bw20_end_freq_to_channel_index(u32 freq_khz)
+{
+int i;
+u32 center_freq = freq_khz - 10000;
+ //Has to compare from high freq to low freq
+ //RF_SUBBAND_5_HIGH_GHZ
+ for (i=RF_CHAN_165;i>=RF_CHAN_149;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_MID_GHZ
+ for (i=RF_CHAN_140;i>=RF_CHAN_100;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_LOW_GHZ
+ for (i=RF_CHAN_64;i>=RF_CHAN_36;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_4_9_GHZ, Ch 216, 212, 208, 252, 248, 244, 240
+ for (i=RF_CHAN_216;i>=RF_CHAN_240;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_2_4_GHZ
+ for (i=RF_CHAN_14;i>=RF_CHAN_1;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+return -1;
+}
+
+static int bw40_start_freq_to_channel_index(u32 freq_khz)
+{
+int i;
+u32 center_freq = freq_khz + 20000;
+ //Has to compare from low freq to high freq
+ //RF_SUBBAND_2_4_GHZ
+ for (i=RF_CHAN_BOND_3;i<=RF_CHAN_BOND_11;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_4_9_GHZ, Ch 242, 246, 250, 210, 214
+ for (i=RF_CHAN_BOND_242;i<=RF_CHAN_BOND_214;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_LOW_GHZ
+ for (i=RF_CHAN_BOND_38;i<=RF_CHAN_BOND_62;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_MID_GHZ
+ for (i=RF_CHAN_BOND_102;i<=RF_CHAN_BOND_138;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_HIGH_GHZ
+ for (i=RF_CHAN_BOND_151;i<=RF_CHAN_BOND_163;i++)
+ if (center_freq <= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+return -1;
+}
+
+static int bw40_end_freq_to_channel_index(u32 freq_khz)
+{
+int i;
+u32 center_freq = freq_khz - 20000;
+ //Has to compare from high freq to low freq
+ //RF_SUBBAND_5_HIGH_GHZ
+ for (i=RF_CHAN_BOND_163;i>=RF_CHAN_BOND_151;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_MID_GHZ
+ for (i=RF_CHAN_BOND_138;i>=RF_CHAN_BOND_102;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_5_LOW_GHZ
+ for (i=RF_CHAN_BOND_62;i>=RF_CHAN_BOND_38;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_4_9_GHZ, Ch 214, 210, 250, 246, 242
+ for (i=RF_CHAN_BOND_214;i>=RF_CHAN_BOND_242;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+ //RF_SUBBAND_2_4_GHZ
+ for (i=RF_CHAN_BOND_11;i>=RF_CHAN_BOND_3;i--)
+ if (center_freq >= (u32) (rfChannels[i].targetFreq) * 1000)
+ return i;
+return -1;
+}
+
+static v_BOOL_t channel_in_capable_band(int j, v_U8_t nBandCapability)
+{
+ switch (nBandCapability)
+ {
+ case eCSR_BAND_ALL:
+ return VOS_TRUE;
+ case eCSR_BAND_24:
+ if (j >= RF_CHAN_1 && j <= RF_CHAN_14)
+ return VOS_TRUE;
+ if (j >= RF_CHAN_BOND_3 && j <= RF_CHAN_BOND_11)
+ return VOS_TRUE; // 2.4G 40MHz channel
+ break;
+ case eCSR_BAND_5G:
+ if (j >= RF_CHAN_240 && j <= RF_CHAN_165)
+ return VOS_TRUE;
+ if (j >= RF_CHAN_BOND_242 && j <= RF_CHAN_BOND_163)
+ return VOS_TRUE; // 2.4G 40MHz channel
+ break;
+ default:
+ break;
+ }
+ return VOS_FALSE;
+}
+
+/* create_crda_regulatory_entry_from_regd should be called during init time */
+static int create_crda_regulatory_entry_from_regd(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ v_U8_t nBandCapability)
+{
+ int i, j, n, domain_id;
+ int bw20_start_channel_index, bw20_end_channel_index;
+ int bw40_start_channel_index, bw40_end_channel_index;
+
+ if (wiphy == NULL || wiphy->regd == NULL)
+ {
+ wiphy_dbg(wiphy, "error: wiphy->regd is NULL\n");
+ return -1;
+ }
+ if (crda_regulatory_entry_valid == VOS_FALSE)
+ domain_id = NUM_REG_DOMAINS-1; /* init time */
+ else
+ domain_id = NUM_REG_DOMAINS-2; /* none-default country */
+ for (n = 0; n < NUM_RF_CHANNELS; n++)
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].enabled = NV_CHANNEL_DISABLE;
+
+ for (i=0;i<wiphy->regd->n_reg_rules;i++)
+ {
+ wiphy_dbg(wiphy, "info: crda rule %d --------------------------------------------\n", i);
+ bw20_start_channel_index =
+ bw20_start_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.start_freq_khz);
+ bw20_end_channel_index =
+ bw20_end_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ if (bw20_start_channel_index == -1 || bw20_end_channel_index == -1)
+ {
+ wiphy_dbg(wiphy, "error: crda freq not supported, start freq (KHz) %d end freq %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ continue; // skip this rull, but continue to next rule
+ }
+ wiphy_dbg(wiphy, "20MHz start freq (KHz) %d end freq %d start ch index %d end ch index %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz,
+ bw20_start_channel_index, bw20_end_channel_index);
+ for (j=bw20_start_channel_index;j<=bw20_end_channel_index;j++)
+ {
+ if (channel_in_capable_band(j, nBandCapability) == VOS_FALSE)
+ {
+ wiphy_dbg(wiphy, "info: CH %d is not in capable band\n",
+ rfChannels[j].channelNum);
+ continue; // skip this channel, continue to next
+ }
+ if (wiphy->regd->reg_rules[i].flags & NL80211_RRF_DFS)
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_DFS;
+ wiphy_dbg(wiphy, "info: CH %d is DFS, max EIRP (mBm) is %d\n", rfChannels[j].channelNum,
+ wiphy->regd->reg_rules[i].power_rule.max_eirp);
+ }
+ else
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_ENABLE;
+ wiphy_dbg(wiphy, "info: CH %d is enabled, no DFS, max EIRP (mBm) is %d\n", rfChannels[j].channelNum,
+ wiphy->regd->reg_rules[i].power_rule.max_eirp);
+ }
+ /* max_eirp is in mBm (= 100 * dBm) unit */
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].pwrLimit =
+ (tANI_S8) ((wiphy->regd->reg_rules[i].power_rule.max_eirp)/100);
+ }
+ /* ignore CRDA max_antenna_gain typical is 3dBi, nv.bin antennaGain is
+ real gain which should be provided by the real design */
+ if (wiphy->regd->reg_rules[i].freq_range.max_bandwidth_khz == 40000)
+ {
+ wiphy_dbg(wiphy, "info: 40MHz (channel bonding) is allowed\n");
+ bw40_start_channel_index =
+ bw40_start_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.start_freq_khz);
+ bw40_end_channel_index =
+ bw40_end_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ if (bw40_start_channel_index == -1 || bw40_end_channel_index == -1)
+ {
+ wiphy_dbg(wiphy, "error: crda freq not supported, start_freq_khz %d end_freq_khz %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ continue; // skip this rull, but continue to next rule
+ }
+ wiphy_dbg(wiphy, "40MHz start freq (KHz) %d end freq %d start ch index %d end ch index %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz,
+ bw40_start_channel_index, bw40_end_channel_index);
+ for (j=bw40_start_channel_index;j<=bw40_end_channel_index;j++)
+ {
+ if (channel_in_capable_band(j, nBandCapability) == VOS_FALSE)
+ continue; // skip this channel, continue to next
+ if (wiphy->regd->reg_rules[i].flags & NL80211_RRF_DFS)
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_DFS;
+ wiphy_dbg(wiphy, "info: 40MHz centered on CH %d is DFS\n", rfChannels[j].channelNum);
+ }
+ else
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_ENABLE;
+ wiphy_dbg(wiphy, "info: 40MHz centered on CH %d is enabled, no DFS\n", rfChannels[j].channelNum);
+ }
+ /* set 40MHz channel power as half (- 3 dB) of 20MHz */
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].pwrLimit =
+ (tANI_S8) (((wiphy->regd->reg_rules[i].power_rule.max_eirp)/100)-3);
+ }
+ }
+ }
+ /* ToDo update other (than DFS) crda regulatory flags (NO_OUTDOOR,
+ NO_OFDM, PASSIVE_SCAN, NO_IBSS) to pnvEFSTable which doesn't add
+ these flags and has no implementation yet. */
+ if (crda_regulatory_entry_valid == VOS_FALSE)
+ { /* init time */
+ crda_alpha2[0] = request->alpha2[0];
+ crda_alpha2[1] = request->alpha2[1];
+ crda_regulatory_entry_valid = VOS_TRUE;
+ }
+ else
+ { /* none-default country */
+ run_time_alpha2[0] = request->alpha2[0];
+ run_time_alpha2[1] = request->alpha2[1];
+ crda_regulatory_run_time_entry_valid = VOS_TRUE;
+ }
+ crda_regulatory_entry_post_processing(wiphy, request, nBandCapability, domain_id);
+ return 0;
+}
+
+#ifdef CONFIG_ENABLE_LINUX_REG
+
+/**------------------------------------------------------------------------
+ \brief vos_nv_setRegDomain -
+ \param clientCtxt - Client Context, Not used for PRIMA
+ regId - Regulatory Domain ID
+ \return status set REG domain operation
+ \sa
+ -------------------------------------------------------------------------*/
+VOS_STATUS vos_nv_setRegDomain(void * clientCtxt, v_REGDOMAIN_t regId)
+{
+
+ if (regId >= REGDOMAIN_COUNT)
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "VOS set reg domain, invalid REG domain ID %d", regId);
+ return VOS_STATUS_E_INVAL;
+ }
+
+ /* Set correct channel information based on REG Domain */
+ regChannels = pnvEFSTable->halnv.tables.regDomains[regId].channels;
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**------------------------------------------------------------------------
+ \brief vos_nv_getRegDomainFromCountryCode() - get the regulatory domain of
+ a country given its country code
+ The \a vos_nv_getRegDomainFromCountryCode() returns the regulatory domain of
+ a country given its country code. This is done from reading a cached
+ copy of the binary file.
+ \param pRegDomain - pointer to regulatory domain
+ \param countryCode - country code
+ \return VOS_STATUS_SUCCESS - regulatory domain is found for the given country
+ VOS_STATUS_E_FAULT - invalid pointer error
+ VOS_STATUS_E_EMPTY - country code table is empty
+ VOS_STATUS_E_EXISTS - given country code does not exist in table
+ \sa
+ -------------------------------------------------------------------------*/
+VOS_STATUS vos_nv_getRegDomainFromCountryCode( v_REGDOMAIN_t *pRegDomain,
+ const v_COUNTRYCODE_t country_code)
+{
+
v_CONTEXT_t pVosContext = NULL;
hdd_context_t *pHddCtx = NULL;
struct wiphy *wiphy = NULL;
int i;
+ int wait_result;
/* sanity checks */
if (NULL == pRegDomain)
@@ -2544,7 +2567,7 @@
*pRegDomain = REGDOMAIN_COUNT;
- if (NULL == countryCode)
+ if (NULL == country_code)
{
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
("Country code array is NULL"));
@@ -2575,83 +2598,69 @@
wiphy = pHddCtx->wiphy;
+ if (false == wiphy->registered)
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ ("wiphy is not yet registered with the kernel") );
+ return VOS_STATUS_E_FAULT;
+ }
/* We need to query the kernel to get the regulatory information
for this country */
-
if (VOS_FALSE == linux_regulatory_init) {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
+ ("init time regdomain request") );
+
/* linux regulatory has not been initialized yet; so the country
information stored with us would not be correct */
/* lookup the country in the local database */
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("init time regdomain request") );
-
temp_reg_domain = REGDOMAIN_COUNT;
for (i = 0; i < countryInfoTable.countryCount &&
REGDOMAIN_COUNT == temp_reg_domain; i++)
{
- if (memcmp(countryCode, countryInfoTable.countryInfo[i].countryCode,
+ if (memcmp(country_code,countryInfoTable.countryInfo[i].countryCode,
VOS_COUNTRY_CODE_LEN) == 0)
{
- /* country code is found */
- /* record the temporary regulatory_domain as well */
+ /* country code is found
+ record the temporary regulatory_domain as well */
temp_reg_domain = countryInfoTable.countryInfo[i].regDomain;
+ break;
}
}
if (REGDOMAIN_COUNT == temp_reg_domain) {
- /* the country was not found in the driver database */
- /* therefore switch to world regulatory domain */
- *pRegDomain = REGDOMAIN_WORLD;
- cur_reg_domain = *pRegDomain;
- linux_reg_cc[0] = '0';
- linux_reg_cc[1] = '0';
- pnvEFSTable->halnv.tables.defaultCountryTable.regDomain =
- *pRegDomain;
+ /* the country was not found in the driver database
+ therefore return failure to the SME/CSR */
- /* since it is the world domain, we are guaranteed
- the entry exists in the kernel regulatory database */
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ ("init time regdomain request"));
- kernel_reg_request_made = VOS_TRUE;
- driver_callback_called = VOS_FALSE;
-
- init_completion(&pHddCtx->linux_reg_req);
- regulatory_hint(wiphy, linux_reg_cc);
- wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
- LINUX_REG_WAIT_TIME);
-
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- ("country code is not found in driver db"));
-
- linux_regulatory_init = VOS_TRUE;
return VOS_STATUS_E_EXISTS;
}
else {
- /* the country code was found in the driver database */
- /* now get the regulatory information from the kernel
+
+ /* the country code was found in the driver database
+ now get the regulatory information from the kernel
database */
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
("country code found in driver db"));
- kernel_reg_request_made = VOS_TRUE;
- driver_callback_called = VOS_FALSE;
-
- init_completion(&pHddCtx->linux_reg_req);
- regulatory_hint(wiphy, countryCode);
- wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
- LINUX_REG_WAIT_TIME);
+ INIT_COMPLETION(pHddCtx->linux_reg_req);
+ regulatory_hint(wiphy, country_code);
+ wait_result = wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
+ LINUX_REG_WAIT_TIME);
/* if the country information does not exist with the kernel, then
the driver callback would not be called */
- if (VOS_TRUE == driver_callback_called) {
+ if (0 == wait_result) {
/* the driver callback was called. this means the country
regulatory information was found in the kernel database.
@@ -2659,51 +2668,32 @@
update the country and the return value for the regulatory
domain */
- *pRegDomain = temp_reg_domain;
- cur_reg_domain = temp_reg_domain;
- linux_reg_cc[0] = countryCode[0];
- linux_reg_cc[1] = countryCode[1];
- pnvEFSTable->halnv.tables.defaultCountryTable.regDomain =
- *pRegDomain;
-
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
("country code is found in kernel db"));
+ *pRegDomain = temp_reg_domain;
+ cur_reg_domain = temp_reg_domain;
+ linux_reg_cc[0] = country_code[0];
+ linux_reg_cc[1] = country_code[1];
+ pnvEFSTable->halnv.tables.defaultCountryTable.regDomain =
+ *pRegDomain;
+
linux_regulatory_init = VOS_TRUE;
return VOS_STATUS_SUCCESS;
}
else {
/* the country information has not been found in the kernel
- database, revert to world domain */
+ database, return failure */
- *pRegDomain = REGDOMAIN_WORLD;
- cur_reg_domain = *pRegDomain;
- linux_reg_cc[0] = '0';
- linux_reg_cc[1] = '0';
- pnvEFSTable->halnv.tables.defaultCountryTable.regDomain =
- *pRegDomain;
-
- /* since it is the world domain, we are guaranteed
- the entry exists in the kernel regulatory database */
-
- kernel_reg_request_made = VOS_TRUE;
- driver_callback_called = VOS_FALSE;
-
- init_completion(&pHddCtx->linux_reg_req);
- regulatory_hint(wiphy, linux_reg_cc);
- wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
- LINUX_REG_WAIT_TIME);
-
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
("country code is not found in kernel db"));
-
- linux_regulatory_init = VOS_TRUE;
return VOS_STATUS_E_EXISTS;
}
}
}
else {
+
/* it is not the init time query but a runtime query. So first
compare the country code with the existing current country code
. If both are same there is no need to query any database */
@@ -2711,14 +2701,15 @@
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
("run time regdomain request"));
- if ((countryCode[0] == linux_reg_cc[0]) &&
- (countryCode[1] == linux_reg_cc[1])) {
+ if ((country_code[0] == linux_reg_cc[0]) &&
+ (country_code[1] == linux_reg_cc[1])) {
/* country code already exists */
- *pRegDomain = cur_reg_domain;
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("NOT NEW country code"));
+ (" country code already exists"));
+
+ *pRegDomain = cur_reg_domain;
return VOS_STATUS_SUCCESS;
}
@@ -2727,68 +2718,50 @@
/* first lookup the country in the local database */
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("NEW country code"));
+ (" new runtime country code"));
for (i = 0; i < countryInfoTable.countryCount &&
REGDOMAIN_COUNT == temp_reg_domain; i++)
{
- if (memcmp(countryCode, countryInfoTable.countryInfo[i].countryCode,
- VOS_COUNTRY_CODE_LEN) == 0)
+ if (memcmp(country_code, countryInfoTable.countryInfo[i].countryCode,
+ VOS_COUNTRY_CODE_LEN) == 0)
{
- /* country code is found */
- /* record the temporary regulatory_domain as well */
+ /* country code is found
+ record the temporary regulatory_domain as well */
temp_reg_domain = countryInfoTable.countryInfo[i].regDomain;
+ break;
}
}
if (REGDOMAIN_COUNT == temp_reg_domain) {
- /* the country was not found in the driver database */
- /* therefore switch to world regulatory domain */
-
- *pRegDomain = REGDOMAIN_WORLD;
- cur_reg_domain = *pRegDomain;
- linux_reg_cc[0] = countryCode[0];
- linux_reg_cc[1] = countryCode[1];
-
- /* since it is the world domain, we are guaranteed
- the entry exists in the kernel regulatory database */
-
- kernel_reg_request_made = VOS_TRUE;
- driver_callback_called = VOS_FALSE;
-
- init_completion(&pHddCtx->linux_reg_req);
- regulatory_hint(wiphy, linux_reg_cc);
- wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
- LINUX_REG_WAIT_TIME);
+ /* the country was not found in the driver database
+ return failure */
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- ("country code is not found in driver db"));
+ ("runtime country code is not found in driver db"));
return VOS_STATUS_E_EXISTS;
}
else {
- /* the country code was found in the driver database */
- /* now get the regulatory information from the kernel
+ /* the country code was found in the driver database
+ now get the regulatory information from the kernel
database */
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- ("country code found in driver db"));
+ ("runtime country code found in driver db"));
- kernel_reg_request_made = VOS_TRUE;
- driver_callback_called = VOS_FALSE;
-
- init_completion(&pHddCtx->linux_reg_req);
- regulatory_hint(wiphy, countryCode);
- wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
- LINUX_REG_WAIT_TIME);
+ INIT_COMPLETION(pHddCtx->linux_reg_req);
+ regulatory_hint(wiphy, country_code);
+ wait_result = wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
+ LINUX_REG_WAIT_TIME);
/* if the country information does not exist with the kernel,
then the driver callback would not be called */
- if (VOS_TRUE == driver_callback_called) {
+ if (0 == wait_result) {
/* the driver callback was called. this means the country
regulatory information was found in the kernel database.
@@ -2796,39 +2769,23 @@
update the country and the return value for the regulatory
domain */
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
+ ("runtime country code is found in kernel db"));
+
*pRegDomain = temp_reg_domain;
cur_reg_domain = temp_reg_domain;
- linux_reg_cc[0] = countryCode[0];
- linux_reg_cc[1] = countryCode[1];
-
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("country code is found in kernel db"));
+ linux_reg_cc[0] = country_code[0];
+ linux_reg_cc[1] = country_code[1];
return VOS_STATUS_SUCCESS;
}
else {
/* the country information has not been found in the kernel
- database, revert to world domain */
-
- *pRegDomain = REGDOMAIN_WORLD;
- cur_reg_domain = *pRegDomain;
- linux_reg_cc[0] = countryCode[0];
- linux_reg_cc[1] = countryCode[1];
-
- /* since it is the world domain, we are guaranteed
- the entry exists in the kernel regulatory database */
-
- kernel_reg_request_made = VOS_TRUE;
- driver_callback_called = VOS_FALSE;
-
- init_completion(&pHddCtx->linux_reg_req);
- regulatory_hint(wiphy, linux_reg_cc);
- wait_for_completion_interruptible_timeout(&pHddCtx->linux_reg_req,
- LINUX_REG_WAIT_TIME);
+ database, return failure */
VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- ("country code is not found in kernel db"));
+ ("runtime country code is not found in kernel db"));
return VOS_STATUS_E_EXISTS;
}
@@ -2837,25 +2794,141 @@
}
}
+
+/* create_crda_regulatory_entry_from_regd should be called during init time */
+static int create_linux_regulatory_entry_from_regd(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ v_U8_t nBandCapability)
+{
+ int i, j, n, domain_id;
+ int bw20_start_channel_index, bw20_end_channel_index;
+ int bw40_start_channel_index, bw40_end_channel_index;
+
+ if (wiphy->regd == NULL)
+ {
+ wiphy_dbg(wiphy, "error: wiphy->regd is NULL\n");
+ return -1;
+ }
+
+ domain_id = temp_reg_domain;
+
+ for (n = 0; n < NUM_RF_CHANNELS; n++)
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[n].enabled = NV_CHANNEL_DISABLE;
+
+ for (i = 0; i < wiphy->regd->n_reg_rules; i++)
+ {
+
+ wiphy_dbg(wiphy, "info: crda rule %d --------------------------------------------\n", i);
+ bw20_start_channel_index =
+ bw20_start_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.start_freq_khz);
+ bw20_end_channel_index =
+ bw20_end_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+
+ if (bw20_start_channel_index == -1 || bw20_end_channel_index == -1)
+ {
+ wiphy_dbg(wiphy, "error: crda freq not supported, start freq (KHz) %d end freq %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ continue; // skip this rull, but continue to next rule
+ }
+
+ wiphy_dbg(wiphy, "20MHz start freq (KHz) %d end freq %d start ch index %d end ch index %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz,
+ bw20_start_channel_index, bw20_end_channel_index);
+
+ for (j=bw20_start_channel_index;j<=bw20_end_channel_index;j++)
+ {
+ if (channel_in_capable_band(j, nBandCapability) == VOS_FALSE)
+ {
+ wiphy_dbg(wiphy, "info: CH %d is not in capable band\n",
+ rfChannels[j].channelNum);
+ continue; // skip this channel, continue to next
+ }
+
+ if (wiphy->regd->reg_rules[i].flags & NL80211_RRF_DFS)
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_DFS;
+ wiphy_dbg(wiphy, "info: CH %d is DFS, max EIRP (mBm) is %d\n", rfChannels[j].channelNum,
+ wiphy->regd->reg_rules[i].power_rule.max_eirp);
+ }
+ else
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_ENABLE;
+ wiphy_dbg(wiphy, "info: CH %d is enabled, no DFS, max EIRP (mBm) is %d\n", rfChannels[j].channelNum,
+ wiphy->regd->reg_rules[i].power_rule.max_eirp);
+ }
+
+ /* max_eirp is in mBm (= 100 * dBm) unit */
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].pwrLimit =
+ (tANI_S8) ((wiphy->regd->reg_rules[i].power_rule.max_eirp)/100);
+ }
+
+ /* ignore CRDA max_antenna_gain typical is 3dBi, nv.bin antennaGain is
+ real gain which should be provided by the real design */
+ if (wiphy->regd->reg_rules[i].freq_range.max_bandwidth_khz == 40000)
+ {
+ wiphy_dbg(wiphy, "info: 40MHz (channel bonding) is allowed\n");
+ bw40_start_channel_index =
+ bw40_start_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.start_freq_khz);
+ bw40_end_channel_index =
+ bw40_end_freq_to_channel_index(wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ if (bw40_start_channel_index == -1 || bw40_end_channel_index == -1)
+ {
+ wiphy_dbg(wiphy, "error: crda freq not supported, start_freq_khz %d end_freq_khz %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz);
+ continue; // skip this rull, but continue to next rule
+ }
+
+ wiphy_dbg(wiphy, "40MHz start freq (KHz) %d end freq %d start ch index %d end ch index %d\n",
+ wiphy->regd->reg_rules[i].freq_range.start_freq_khz,
+ wiphy->regd->reg_rules[i].freq_range.end_freq_khz,
+ bw40_start_channel_index, bw40_end_channel_index);
+ for (j=bw40_start_channel_index;j<=bw40_end_channel_index;j++)
+ {
+ if (channel_in_capable_band(j, nBandCapability) == VOS_FALSE)
+ continue; // skip this channel, continue to next
+ if (wiphy->regd->reg_rules[i].flags & NL80211_RRF_DFS)
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_DFS;
+ wiphy_dbg(wiphy, "info: 40MHz centered on CH %d is DFS\n", rfChannels[j].channelNum);
+ }
+ else
+ {
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].enabled = NV_CHANNEL_ENABLE;
+ wiphy_dbg(wiphy, "info: 40MHz centered on CH %d is enabled, no DFS\n", rfChannels[j].channelNum);
+ }
+ /* set 40MHz channel power as half (- 3 dB) of 20MHz */
+ pnvEFSTable->halnv.tables.regDomains[domain_id].channels[j].pwrLimit =
+ (tANI_S8) (((wiphy->regd->reg_rules[i].power_rule.max_eirp)/100)-3);
+ }
+ }
+ }
+
+ return 0;
+}
+
/*
* Function: wlan_hdd_linux_reg_notifier
* This function is called from cfg80211 core to provide regulatory settings
* after new country is requested or intersected (init, user input or 11d)
+ * This function is used to create a CRDA regulatory settings entry into internal
+ * regulatory setting table.
*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
void wlan_hdd_linux_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
#else
-void wlan_hdd_linux_reg_notifier(struct wiphy *wiphy,
+int wlan_hdd_linux_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
#endif
{
-
- v_REGDOMAIN_t reg_domain = REGDOMAIN_COUNT;
hdd_context_t *pHddCtx = wiphy_priv(wiphy);
+ tANI_U8 nBandCapability;
- wiphy_dbg(wiphy, "info: cfg80211 reg_notifier callback for country"
- " %c%c\n", request->alpha2[0], request->alpha2[1]);
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
+ ("cfg80211 reg notifier callback for country"));
if (pHddCtx->isLoadUnloadInProgress)
{
@@ -2865,48 +2938,72 @@
}
/* first check if this callback is in response to the driver callback */
- if (VOS_TRUE == kernel_reg_request_made) {
+ if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER)
+ {
- /* this is the driver query to the kernel. the regulatory domain was
- temporarily calculated by the entity that made the kernel query.
- Use that to update the internal database */
+ nBandCapability = pHddCtx->cfg_ini->nBandCapability;
- reg_domain = temp_reg_domain;
- create_linux_regulatory_entry_driver(wiphy, request,
- pHddCtx->cfg_ini->nBandCapability,
- reg_domain);
+ if (create_linux_regulatory_entry_from_regd(wiphy, request, pHddCtx->cfg_ini->nBandCapability) == 0)
+ {
- driver_callback_called = VOS_TRUE;
- kernel_reg_request_made = VOS_FALSE;
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
+ (" regulatory entry created"));
+ }
- complete(&pHddCtx->linux_reg_req);
-
- }
- else {
-
-
- /* this callback is not in response to driver callback.
- we should contact the lower layers(sme_ChangeCountryCode ??)
- with this information. Depending on whether the lower layer
- recommends changing the country code or not, we can update the
- internal database */
-
- /*
- ret_val = create_linux_regulatory_entry_other(wiphy, request,
- pHddCtx->cfg_ini->nBandCapability,
- reg_domain);
- */
-
+ complete(&pHddCtx->linux_reg_req);
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
return;
+#else
+ return 0;
+#endif
}
-
#else
/**------------------------------------------------------------------------
+ \brief vos_nv_setRegDomain -
+ \param clientCtxt - Client Context, Not used for PRIMA
+ regId - Regulatory Domain ID
+ \return status set REG domain operation
+ \sa
+ -------------------------------------------------------------------------*/
+VOS_STATUS vos_nv_setRegDomain(void * clientCtxt, v_REGDOMAIN_t regId)
+{
+ v_CONTEXT_t pVosContext = NULL;
+ hdd_context_t *pHddCtx = NULL;
+ struct wiphy *wiphy = NULL;
+ /* Client Context Argumant not used for PRIMA */
+ if (regId >= REGDOMAIN_COUNT)
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "VOS set reg domain, invalid REG domain ID %d", regId);
+ return VOS_STATUS_E_INVAL;
+ }
+
+ pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ if (NULL != pVosContext)
+ pHddCtx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext);
+ else
+ return VOS_STATUS_E_EXISTS;
+ /* Set correct channel information based on REG Domain */
+ regChannels = pnvEFSTable->halnv.tables.regDomains[regId].channels;
+
+ /* when CRDA is not running then we are world roaming.
+ In this case if 11d is enabled, then country code should
+ be update on basis of world roaming */
+ if (NULL != pHddCtx)
+ {
+ wiphy = pHddCtx->wiphy;
+ regulatory_hint(wiphy, "00");
+ }
+ return VOS_STATUS_SUCCESS;
+}
+
+
+/**------------------------------------------------------------------------
\brief vos_nv_getRegDomainFromCountryCode() - get the regulatory domain of
a country given its country code
The \a vos_nv_getRegDomainFromCountryCode() returns the regulatory domain of
@@ -2923,121 +3020,317 @@
VOS_STATUS vos_nv_getRegDomainFromCountryCode( v_REGDOMAIN_t *pRegDomain,
const v_COUNTRYCODE_t countryCode )
{
- int i;
+ int i;
+ v_CONTEXT_t pVosContext = NULL;
+ hdd_context_t *pHddCtx = NULL;
+ struct wiphy *wiphy = NULL;
+ int status;
+ // sanity checks
+ if (NULL == pRegDomain)
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ ("Invalid reg domain pointer\n") );
+ return VOS_STATUS_E_FAULT;
+ }
+ *pRegDomain = REGDOMAIN_COUNT;
- if (NULL == pRegDomain)
+ if (NULL == countryCode)
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ ("Country code array is NULL\r\n") );
+ return VOS_STATUS_E_FAULT;
+ }
+ if (0 == countryInfoTable.countryCount)
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ ("Reg domain table is empty\r\n") );
+ return VOS_STATUS_E_EMPTY;
+ }
+ /* If CRDA regulatory settings is valid, i.e. crda is enabled
+ and reg_notifier is called back.
+ Intercept here and redirect to the Reg domain table's CRDA
+ entry if country code is crda's country.
+ last one NUM_REG_DOMAINS-1 is reserved for crda */
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
+ "vos_nv_getRegDomainFromCountryCode %c%c\n",
+ countryCode[0], countryCode[1]);
+
+ if (crda_regulatory_entry_valid == VOS_TRUE)
+ {
+ if (crda_alpha2[0]==countryCode[0] && crda_alpha2[1]==countryCode[1])
+ {
+ *pRegDomain = NUM_REG_DOMAINS-1;
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
+ "vos_nv_getRegDomainFromCountryCode return crda init entry\n");
+ return VOS_STATUS_SUCCESS;
+ }
+ if (run_time_alpha2[0]==countryCode[0] &&
+ run_time_alpha2[1]==countryCode[1] &&
+ crda_regulatory_run_time_entry_valid == VOS_TRUE)
+ {
+ *pRegDomain = NUM_REG_DOMAINS-2;
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
+ "vos_nv_getRegDomainFromCountryCode return crda none-default country entry\n");
+ return VOS_STATUS_SUCCESS;
+ }
+ else
+ {
+ crda_regulatory_run_time_entry_valid = VOS_FALSE;
+ pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ if (NULL != pVosContext)
+ pHddCtx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext);
+ else
+ return VOS_STATUS_E_EXISTS;
+ if (NULL == pHddCtx)
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ ("Invalid pHddCtx pointer\r\n") );
+ return VOS_STATUS_E_FAULT;
+ }
+
+ wiphy = pHddCtx->wiphy;
+
+ INIT_COMPLETION(pHddCtx->driver_crda_req);
+ regulatory_hint(wiphy, countryCode);
+ status = wait_for_completion_interruptible_timeout(
+ &pHddCtx->driver_crda_req,
+ msecs_to_jiffies(CRDA_WAIT_TIME));
+ if (!status)
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Timeout waiting for CRDA REQ", __func__);
+ }
+
+ if (crda_regulatory_run_time_entry_valid == VOS_TRUE)
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO_HIGH,
+ "vos_nv_getRegDomainFromCountryCode return crda new none-default country entry\n");
+ return VOS_STATUS_SUCCESS;
+ }
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "vos_nv_getRegDomainFromCountryCode failed to get crda new none-default country entry\n");
+ return VOS_STATUS_E_EXISTS;
+ }
+ }
+
+ // iterate the country info table until end of table or the country code
+ // is found
+ for (i = 0; i < countryInfoTable.countryCount &&
+ REGDOMAIN_COUNT == *pRegDomain; i++)
+ {
+ if (memcmp(countryCode, countryInfoTable.countryInfo[i].countryCode,
+ VOS_COUNTRY_CODE_LEN) == 0)
+ {
+ // country code is found
+ *pRegDomain = countryInfoTable.countryInfo[i].regDomain;
+ }
+ }
+ if (REGDOMAIN_COUNT != *pRegDomain)
+ {
+ return VOS_STATUS_SUCCESS;
+ }
+ else
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
+ ("country code is not found\r\n"));
+ return VOS_STATUS_E_EXISTS;
+ }
+}
+
+
+/*
+ * Function: wlan_hdd_crda_reg_notifier
+ * This function is called from cfg80211 core to provide regulatory settings
+ * after new country is requested or intersected (init, user input or 11d)
+ * This function is used to create a CRDA regulatory settings entry into internal
+ * regulatory setting table.
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+void wlan_hdd_crda_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+#else
+int wlan_hdd_crda_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+#endif
+{
+ hdd_context_t *pHddCtx = wiphy_priv(wiphy);
+ v_REGDOMAIN_t domainIdCurrent;
+ tANI_U8 ccode[WNI_CFG_COUNTRY_CODE_LEN];
+ tANI_U8 uBufLen = WNI_CFG_COUNTRY_CODE_LEN;
+ tANI_U8 nBandCapability;
+ int i,j,k,m;
+
+ wiphy_dbg(wiphy, "info: cfg80211 reg_notifier callback for country"
+ " %c%c\n", request->alpha2[0], request->alpha2[1]);
+ if (request->initiator == NL80211_REGDOM_SET_BY_USER)
{
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("Invalid reg domain pointer") );
- return VOS_STATUS_E_FAULT;
+ wiphy_dbg(wiphy, "info: set by user\n");
+ if (create_crda_regulatory_entry(wiphy, request, pHddCtx->cfg_ini->nBandCapability) != 0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ return;
+#else
+ return 0;
+#endif
+ // ToDo
+ /* Don't change default country code to CRDA country code by user req */
+ /* Shouldcall sme_ChangeCountryCode to send a message to trigger read
+ regd for new country settings */
+ //sme_ChangeCountryCode(pHddCtx->hHal, NULL,
+ // &country_code[0], pAdapter, pHddCtx->pvosContext);
}
-
- *pRegDomain = REGDOMAIN_COUNT;
-
- if (NULL == countryCode)
+ else if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
{
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("Country code array is NULL") );
- return VOS_STATUS_E_FAULT;
- }
+ wiphy_dbg(wiphy, "info: set by country IE\n");
+ if (create_crda_regulatory_entry(wiphy, request, pHddCtx->cfg_ini->nBandCapability) != 0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ return;
+#else
+ return 0;
+#endif
+ // ToDo
+ /* Intersect of 11d and crda settings */
- if (0 == countryInfoTable.countryCount)
+ /* Don't change default country code to CRDA country code by 11d req */
+ /* for every adapter call sme_ChangeCountryCode to trigger read regd
+ for intersected new country settings */
+ // sme_ChangeCountryCode(pHddCtx->hHal, NULL,
+ // &country_code[0], pAdapter, pHddCtx->pvosContext);
+ }
+ else if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+ (request->initiator == NL80211_REGDOM_SET_BY_CORE))
{
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
- ("Reg domain table is empty") );
- return VOS_STATUS_E_EMPTY;
+ if ( eHAL_STATUS_SUCCESS != sme_GetCountryCode(pHddCtx->hHal, ccode, &uBufLen))
+ {
+ wiphy_dbg(wiphy, "info: set by driver CCODE ERROR\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ return;
+#else
+ return 0;
+#endif
+ }
+ if (eHAL_STATUS_SUCCESS != sme_GetRegulatoryDomainForCountry (pHddCtx->hHal,
+ ccode, (v_REGDOMAIN_t *) &domainIdCurrent))
+ {
+ wiphy_dbg(wiphy, "info: set by driver ERROR\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ return;
+#else
+ return 0;
+#endif
+ }
+
+ wiphy_dbg(wiphy, "country: %c%c set by driver\n",ccode[0],ccode[1]);
+ /* if set by driver itself, it means driver can accept the crda
+ regulatory settings and wiphy->regd should be populated with crda
+ settings. iwiphy->bands doesn't seem to set ht40 flags in kernel
+ correctly, this may be fixed by later kernel */
+
+ nBandCapability = pHddCtx->cfg_ini->nBandCapability;
+ for (i = 0, m = 0; i < IEEE80211_NUM_BANDS; i++)
+ {
+ if (NULL == wiphy->bands[i])
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "error: wiphy->bands[i] is NULL, i = %d", i);
+ continue;
+ }
+
+ // internal channels[] is one continous array for both 2G and 5G bands
+ // m is internal starting channel index for each band
+ if (0 == i)
+ {
+ m = 0;
+ }
+ else
+ {
+ m = wiphy->bands[i-1]?wiphy->bands[i-1]->n_channels + m:m;
+ }
+
+ for (j=0; j<wiphy->bands[i]->n_channels; j++)
+ {
+ // k = (m + j) is internal current channel index for 20MHz channel
+ // n is internal channel index for corresponding 40MHz channel
+ k = m + j;
+ if (IEEE80211_BAND_2GHZ == i && eCSR_BAND_5G == nBandCapability) // 5G only
+ {
+ // Enable social channels for P2P
+ if ((2412 == wiphy->bands[i]->channels[j].center_freq ||
+ 2437 == wiphy->bands[i]->channels[j].center_freq ||
+ 2462 == wiphy->bands[i]->channels[j].center_freq ) &&
+ NV_CHANNEL_ENABLE == regChannels[k].enabled)
+ {
+ wiphy->bands[i]->channels[j].flags &= ~IEEE80211_CHAN_DISABLED;
+ }
+ else
+ {
+ wiphy->bands[i]->channels[j].flags |= IEEE80211_CHAN_DISABLED;
+ }
+ continue;
+ }
+ else if (IEEE80211_BAND_5GHZ == i && eCSR_BAND_24 == nBandCapability) // 2G only
+ {
+ wiphy->bands[i]->channels[j].flags |= IEEE80211_CHAN_DISABLED;
+ continue;
+ }
+
+ if (NV_CHANNEL_DISABLE == regChannels[k].enabled ||
+ NV_CHANNEL_INVALID == regChannels[k].enabled)
+ {
+ wiphy->bands[i]->channels[j].flags |= IEEE80211_CHAN_DISABLED;
+ }
+ else if (NV_CHANNEL_DFS == regChannels[k].enabled)
+ {
+ wiphy->bands[i]->channels[j].flags &= ~(IEEE80211_CHAN_DISABLED
+ |IEEE80211_CHAN_RADAR);
+ wiphy->bands[i]->channels[j].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+ else
+ {
+ wiphy->bands[i]->channels[j].flags &= ~(IEEE80211_CHAN_DISABLED
+ |IEEE80211_CHAN_PASSIVE_SCAN
+ |IEEE80211_CHAN_NO_IBSS
+ |IEEE80211_CHAN_RADAR);
+ }
+ }
+ }
+
+ /* Haven't seen any condition that will set by driver after init.
+ If we do, then we should also call sme_ChangeCountryCode */
+ if (wiphy->bands[IEEE80211_BAND_5GHZ])
+ {
+ for (j=0; j<wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels; j++)
+ {
+ // p2p UNII-1 band channels are passive when domain is FCC.
+ if ((wiphy->bands[IEEE80211_BAND_5GHZ ]->channels[j].center_freq == 5180 ||
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5200 ||
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5220 ||
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5240) &&
+ (ccode[0]== 'U'&& ccode[1]=='S'))
+ {
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+ else if ((wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5180 ||
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5200 ||
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5220 ||
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].center_freq == 5240) &&
+ (ccode[0]!= 'U'&& ccode[1]!='S'))
+ {
+ wiphy->bands[IEEE80211_BAND_5GHZ]->channels[j].flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+ }
+ }
+
+ if (request->initiator == NL80211_REGDOM_SET_BY_CORE)
+ {
+ request->processed = 1;
+ }
}
- if (VOS_FALSE == driver_regulatory_init) {
-
- /*
- iterate the country info table until end of table or the country code
- is found
- */
-
- for (i = 0; i < countryInfoTable.countryCount &&
- REGDOMAIN_COUNT == *pRegDomain; i++)
- {
- if (memcmp(countryCode, countryInfoTable.countryInfo[i].countryCode,
- VOS_COUNTRY_CODE_LEN) == 0)
- {
- /* country code is found */
- *pRegDomain = countryInfoTable.countryInfo[i].regDomain;
- }
- }
-
- if (REGDOMAIN_COUNT != *pRegDomain)
- {
- driver_reg_cc[0] = countryCode[0];
- driver_reg_cc[1] = countryCode[1];
- cur_reg_domain = *pRegDomain;
- driver_regulatory_init = VOS_TRUE;
-
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("init time country code is found in driver db"));
-
- return VOS_STATUS_SUCCESS;
- }
- else
- {
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- ("init time country code is not found in driver db"));
-
- return VOS_STATUS_E_EXISTS;
- }
- }
- else {
- if ((countryCode[0] == driver_reg_cc[0]) &&
- (countryCode[1] == driver_reg_cc[1])) {
-
- *pRegDomain = cur_reg_domain;
-
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("run time country code has not changed"));
-
- return VOS_STATUS_SUCCESS;
- }
- else {
-
- /* iterate the country info table until end of table or the
- country code is found
- */
-
- for (i = 0; i < countryInfoTable.countryCount &&
- REGDOMAIN_COUNT == *pRegDomain; i++)
- {
- if (memcmp(countryCode, countryInfoTable.countryInfo[i].countryCode,
- VOS_COUNTRY_CODE_LEN) == 0)
- {
- /* country code is found */
- *pRegDomain = countryInfoTable.countryInfo[i].regDomain;
- }
- }
-
- if (REGDOMAIN_COUNT != *pRegDomain)
- {
- driver_reg_cc[0] = countryCode[0];
- driver_reg_cc[1] = countryCode[1];
- cur_reg_domain = *pRegDomain;
-
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
- ("run time country code is found in driver db"));
-
- return VOS_STATUS_SUCCESS;
- }
- else
- {
- VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_WARN,
- ("run time country code is not found in driver db"));
-
- driver_reg_cc[0] = 0;
- driver_reg_cc[1] = 0;
- driver_regulatory_init = VOS_FALSE;
-
- return VOS_STATUS_E_EXISTS;
- }
- }
- }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
+ return;
+#else
+ return 0;
+#endif
}
#endif