You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
505 lines
17 KiB
505 lines
17 KiB
/* Copyright Statement: |
|
* * |
|
* * This software/firmware and related documentation ("MediaTek Software") are |
|
* * protected under relevant copyright laws. The information contained herein |
|
* * is confidential and proprietary to MediaTek Inc. and/or its licensors. |
|
* * Without the prior written permission of MediaTek inc. and/or its licensors, |
|
* * any reproduction, modification, use or disclosure of MediaTek Software, |
|
* * and information contained herein, in whole or in part, shall be strictly prohibited. |
|
* * |
|
* * MediaTek Inc. (C) 2016. All rights reserved. |
|
* * |
|
* * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
|
* * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
|
* * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON |
|
* * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
|
* * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
|
* * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
|
* * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
|
* * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
|
* * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH |
|
* * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES |
|
* * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES |
|
* * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK |
|
* * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
|
* * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND |
|
* * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
|
* * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
|
* * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO |
|
* * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
|
* * |
|
* * The following software/firmware and/or related documentation ("MediaTek Software") |
|
* * have been modified by MediaTek Inc. All revisions are subject to any receiver's |
|
* * applicable license agreements with MediaTek Inc. |
|
* */ |
|
|
|
#define LOG_TAG "bt_mtk_stack_config" |
|
|
|
#include "mtk_stack_config.h" |
|
|
|
#include <stdint.h> |
|
#include <unistd.h> // access() |
|
#include <algorithm> |
|
#include <iomanip> |
|
#include <iterator> |
|
#include <map> |
|
#include <sstream> |
|
#include <string> |
|
#include <vector> |
|
|
|
#include <base/logging.h> |
|
#include <base/memory/singleton.h> |
|
|
|
#include "hci_internals.h" |
|
#include "log_mode.h" |
|
#include "mtk_util.h" |
|
#include "osi/include/list.h" |
|
#include "osi/include/log.h" |
|
#include "osi/include/properties.h" |
|
|
|
namespace vendor { |
|
namespace mediatek { |
|
namespace bluetooth { |
|
namespace stack { |
|
|
|
static const std::string kPath("/etc/bluetooth/"); |
|
static const std::string kStackConf("mtk_bt_stack.conf"); |
|
static const std::string kControllerConf("mtk_bt_fw.conf"); |
|
|
|
class StackConfigParser { |
|
public: |
|
StackConfigParser() : kMtkBtStackConf_(kPath + kStackConf) { |
|
stack_trace_["TRC_BTM"] = 0; |
|
stack_trace_["TRC_HCI"] = 0; |
|
stack_trace_["TRC_L2CAP"] = 0; |
|
stack_trace_["TRC_RFCOMM"] = 0; |
|
stack_trace_["TRC_OBEX"] = 0; |
|
stack_trace_["TRC_AVCT"] = 0; |
|
stack_trace_["TRC_AVDT"] = 0; |
|
stack_trace_["TRC_AVRC"] = 0; |
|
stack_trace_["TRC_AVDT_SCB"] = 0; |
|
stack_trace_["TRC_AVDT_CCB"] = 0; |
|
stack_trace_["TRC_A2D"] = 0; |
|
stack_trace_["TRC_SDP"] = 0; |
|
stack_trace_["TRC_GATT"] = 0; |
|
stack_trace_["TRC_SMP"] = 0; |
|
stack_trace_["TRC_BTAPP"] = 0; |
|
stack_trace_["TRC_BTIF"] = 0; |
|
stack_trace_["TRC_GAP"] = 0; |
|
stack_trace_["TRC_BNEP"] = 0; |
|
stack_trace_["TRC_PAN"] = 0; |
|
stack_trace_["TRC_HID_HOST"] = 0; |
|
stack_trace_["TRC_HID_DEV"] = 0; |
|
vlog_setting_["LoggingV"] = "--v=0"; |
|
vlog_setting_["LoggingVModule"] = |
|
"--vmodule=*/btm/*=1,btm_ble_multi*=2,btif_*=1"; |
|
} |
|
|
|
config_t* OverwriteConfig(config_t* config) { |
|
CHECK(config != NULL); |
|
config_t* mtk_config = config_new(kMtkBtStackConf_.c_str()); |
|
if (!mtk_config) { |
|
LOG_ERROR(LOG_TAG, "%s file %s not found!", __func__, |
|
kMtkBtStackConf_.c_str()); |
|
} else { |
|
for (auto& it : stack_trace_) { |
|
if (config_has_key(config, CONFIG_DEFAULT_SECTION, it.first.c_str()) && |
|
config_has_key(mtk_config, CONFIG_DEFAULT_SECTION, |
|
it.first.c_str())) { |
|
it.second = config_get_int(mtk_config, CONFIG_DEFAULT_SECTION, |
|
it.first.c_str(), it.second); |
|
config_set_int(config, CONFIG_DEFAULT_SECTION, it.first.c_str(), |
|
it.second); |
|
LOG_INFO(LOG_TAG, "%s Overwrite: %s = %d", __func__, it.first.c_str(), |
|
it.second); |
|
} |
|
} |
|
for (auto& it : vlog_setting_) { |
|
if (config_has_key(mtk_config, CONFIG_DEFAULT_SECTION, |
|
it.first.c_str())) { |
|
it.second = config_get_string(mtk_config, CONFIG_DEFAULT_SECTION, |
|
it.first.c_str(), it.second.c_str()); |
|
config_set_string(config, CONFIG_DEFAULT_SECTION, it.first.c_str(), |
|
it.second.c_str()); |
|
LOG_INFO(LOG_TAG, "%s Overwrite: %s = %s", __func__, it.first.c_str(), |
|
it.second.c_str()); |
|
} |
|
} |
|
} |
|
return config; |
|
} |
|
|
|
private: |
|
const std::string kMtkBtStackConf_; |
|
std::map<std::string, int> stack_trace_; |
|
std::map<std::string, std::string> vlog_setting_; |
|
}; |
|
|
|
class ControllerLogModeParser { |
|
public: |
|
explicit ControllerLogModeParser(TraceLevel level) : trace_level_(level) {} |
|
virtual ~ControllerLogModeParser() {} |
|
|
|
virtual std::vector<uint8_t> GetEnableCommandPacket() const = 0; |
|
virtual std::vector<uint8_t> GetFilterommandPacket() const = 0; |
|
|
|
protected: |
|
TraceLevel GetTraceLevel() const { return trace_level_; } |
|
|
|
private: |
|
TraceLevel trace_level_; |
|
}; |
|
|
|
class ControllerLogModeDefaultParser : public ControllerLogModeParser { |
|
public: |
|
explicit ControllerLogModeDefaultParser(TraceLevel level) |
|
: ControllerLogModeParser(level) { |
|
InitEnableCmdPackets(); |
|
InitFilterCmdPackets(); |
|
} |
|
virtual ~ControllerLogModeDefaultParser() {} |
|
|
|
std::vector<uint8_t> GetEnableCommandPacket() const override { |
|
return enable_cmd_packets_[GetTraceLevel()]; |
|
} |
|
|
|
std::vector<uint8_t> GetFilterommandPacket() const override { |
|
return filter_cmd_packets_[GetTraceLevel()]; |
|
} |
|
|
|
private: |
|
void InitEnableCmdPackets() { |
|
// kDefault |
|
enable_cmd_packets_.push_back(std::vector<uint8_t>{0xBE, 0xFC, 0x01, 0x00}); |
|
// kSqc |
|
enable_cmd_packets_.push_back(std::vector<uint8_t>{0xBE, 0xFC, 0x01, 0x05}); |
|
// kDebug |
|
enable_cmd_packets_.push_back(std::vector<uint8_t>{0xBE, 0xFC, 0x01, 0x05}); |
|
} |
|
|
|
void InitFilterCmdPackets() { |
|
// kDefault |
|
filter_cmd_packets_.push_back(std::vector<uint8_t>{ |
|
// C2 FC5F filter |
|
0x5F, 0xFC, 0x2A, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00, |
|
// C201 SYS |
|
0x00, 0x00, 0x00, 0x00, |
|
// C202 TIM |
|
0x00, 0x00, 0x00, 0x00, |
|
// C203 PKV |
|
0x00, 0x00, 0x00, 0x00, |
|
// C204 LC |
|
0x00, 0x00, 0x00, 0x00, |
|
// C205 LL |
|
0x00, 0x00, 0x00, 0x00, |
|
// C206 ANT |
|
0x00, 0x00, 0x00, 0x00, |
|
// C207 LMP |
|
0x00, 0x00, 0x00, 0x00, |
|
// C208 CO |
|
0x00, 0x00, 0x00, 0x00, |
|
// C209 VOICE |
|
0x00, 0x00, 0x00, 0x00}); |
|
// kSqc |
|
filter_cmd_packets_.push_back(std::vector<uint8_t>{ |
|
// C2 FC5F filter |
|
0x5F, 0xFC, 0x2A, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00, |
|
// C201 SYS |
|
0x00, 0x00, 0x00, 0x88, |
|
// C202 TIM |
|
0x00, 0x00, 0x00, 0x00, |
|
// C203 PKV |
|
0x00, 0x00, 0x00, 0x00, |
|
// C204 LC |
|
0x00, 0x00, 0x00, 0x00, |
|
// C205 LL |
|
0x00, 0x00, 0x00, 0x00, |
|
// C206 ANT |
|
0x00, 0x00, 0x00, 0x00, |
|
// C207 LMP |
|
0x00, 0x00, 0x00, 0x00, |
|
// C208 CO |
|
0x00, 0x00, 0x00, 0x00, |
|
// C209 VOICE |
|
0x00, 0x00, 0x00, 0x00}); |
|
|
|
// kDebug |
|
filter_cmd_packets_.push_back(std::vector<uint8_t>{ |
|
// C2 FC5F filter |
|
0x5F, 0xFC, 0x2A, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00, |
|
// C201 SYS |
|
0x00, 0x00, 0x00, 0xCC, |
|
// C202 TIM |
|
0x00, 0x00, 0x00, 0x00, |
|
// C203 PKV |
|
0x00, 0x00, 0x00, 0x00, |
|
// C204 LC |
|
0x1F, 0xF0, 0x00, 0x00, |
|
// C205 LL |
|
0x07, 0x27, 0x06, 0x00, |
|
// C206 ANT |
|
0x00, 0x00, 0x00, 0x00, |
|
// C207 LMP |
|
0x03, 0x00, 0x03, 0x00, |
|
// C208 CO |
|
0x03, 0x08, 0x00, 0x00, |
|
// C209 VOICE |
|
0x00, 0x00, 0x00, 0x00}); |
|
} |
|
|
|
std::vector<std::vector<uint8_t> > enable_cmd_packets_; |
|
std::vector<std::vector<uint8_t> > filter_cmd_packets_; |
|
}; |
|
|
|
class ControllerLogModeConfParser : public ControllerLogModeParser { |
|
public: |
|
explicit ControllerLogModeConfParser(TraceLevel level) |
|
: ControllerLogModeParser(level), kSerialTypeLen_(1) { |
|
InitSections(); |
|
InitConfig(); |
|
} |
|
virtual ~ControllerLogModeConfParser() { |
|
if (config_) { |
|
config_free(config_); |
|
} |
|
} |
|
|
|
std::vector<uint8_t> GetEnableCommandPacket() const override { |
|
return LoadEnableCommandData(GetTraceLevel()); |
|
} |
|
|
|
std::vector<uint8_t> GetFilterommandPacket() const override { |
|
return LoadFilterCommandData(GetTraceLevel()); |
|
} |
|
|
|
private: |
|
void InitSections() { |
|
sections_[kDefault] = std::string("MtkBtFwLogOff"); |
|
sections_[kSqc] = std::string("MtkBtFwLogSqc"); |
|
sections_[kDebug] = std::string("MtkBtFwLogDebug"); |
|
} |
|
|
|
void InitConfig() { |
|
config_ = config_new(std::string(kPath + kControllerConf).c_str()); |
|
CHECK(config_ != NULL); |
|
} |
|
|
|
std::vector<uint8_t> LoadEnableCommandData(TraceLevel level) const { |
|
const std::string kEnableCmdKey("C1"); |
|
std::string cmd_temp(config_get_string(config_, sections_.at(level).c_str(), |
|
kEnableCmdKey.c_str(), NULL)); |
|
std::vector<uint8_t> cmd_data = ConvertCmdStringToData(cmd_temp); |
|
std::vector<uint8_t> enable_cmd; |
|
// Skip to add serial type bit |
|
std::copy(cmd_data.begin() + kSerialTypeLen_, cmd_data.end(), |
|
std::back_inserter(enable_cmd)); |
|
return enable_cmd; |
|
} |
|
|
|
std::vector<uint8_t> LoadFilterCommandData(TraceLevel level) const { |
|
const std::string kFilterCmdKey("C2"); |
|
constexpr int kC2NumOfRows(10); |
|
std::string cmd_temp(config_get_string(config_, sections_.at(level).c_str(), |
|
kFilterCmdKey.c_str(), NULL)); |
|
for (int i(1); i < kC2NumOfRows; i++) { |
|
std::stringstream ss; |
|
ss << kFilterCmdKey << std::setfill('0') << std::setw(2) << i; |
|
std::string cmdx(config_get_string(config_, sections_.at(level).c_str(), |
|
ss.str().c_str(), NULL)); |
|
cmd_temp += std::string(" ") + cmdx; |
|
} |
|
std::vector<uint8_t> cmd_data = ConvertCmdStringToData(cmd_temp); |
|
std::vector<uint8_t> filter_cmd; |
|
// Skip to add serial type bit |
|
std::copy(cmd_data.begin() + kSerialTypeLen_, cmd_data.end(), |
|
std::back_inserter(filter_cmd)); |
|
return filter_cmd; |
|
} |
|
|
|
static uint8_t StringToUInt8(const std::string& str) { |
|
return static_cast<uint8_t>(std::stoi(str, nullptr, 16)); |
|
} |
|
|
|
std::vector<uint8_t> ConvertCmdStringToData(const std::string& cmd) const { |
|
std::istringstream iss(cmd); |
|
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss}, |
|
std::istream_iterator<std::string>{}}; |
|
std::vector<uint8_t> data(tokens.size(), 0); |
|
std::transform(tokens.begin(), tokens.end(), data.begin(), StringToUInt8); |
|
return data; |
|
} |
|
|
|
const int kSerialTypeLen_; |
|
|
|
config_t* config_; |
|
std::map<TraceLevel, std::string> sections_; |
|
}; |
|
|
|
class ControllerLogModeFactory : public Singleton<ControllerLogModeFactory> { |
|
public: |
|
std::shared_ptr<ControllerLogModeParser> Create(TraceLevel level); |
|
|
|
private: |
|
friend class Singleton<ControllerLogModeFactory>; |
|
}; |
|
|
|
std::shared_ptr<ControllerLogModeParser> ControllerLogModeFactory::Create( |
|
TraceLevel level) { |
|
if (access(std::string(kPath + kControllerConf).c_str(), F_OK)) { |
|
return std::shared_ptr<ControllerLogModeParser>( |
|
new ControllerLogModeDefaultParser(level)); |
|
} else { |
|
return std::shared_ptr<ControllerLogModeParser>( |
|
new ControllerLogModeConfParser(level)); |
|
} |
|
} |
|
|
|
class BTStackLogConfig : public Singleton<BTStackLogConfig> { |
|
public: |
|
bool IsNeedOverWriteConfig() const { |
|
TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kStack); |
|
return (kDebug == level) || (kSqc == level); |
|
} |
|
|
|
bool IsBTSnoopEnabled() const { |
|
if (isPropertySet(kBTSnoopEnableProperty_.c_str())) { |
|
return IsBTSnoopFeatureEnabled(kBTSnoopEnableProperty_.c_str()); |
|
} else { |
|
TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kStack); |
|
return (kDebug == level) || (kSqc == level); |
|
} |
|
} |
|
|
|
bool IsBTSnoopSaveLastEnabled() const { |
|
if (isPropertySet(kBTSnoopShouldSaveLastProperty_.c_str())) { |
|
return IsBTSnoopFeatureEnabled(kBTSnoopShouldSaveLastProperty_.c_str()); |
|
} else { |
|
TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kStack); |
|
return (kDebug == level) || (kSqc == level); |
|
} |
|
} |
|
|
|
bool IsInboundDataMonitorEnabled() const { |
|
if (isPropertySet(kBTForceTurnOffInboundDataMonitorProperty_.c_str())) { |
|
return !IsBTSnoopFeatureEnabled( |
|
kBTForceTurnOffInboundDataMonitorProperty_.c_str()); |
|
} else { |
|
return IsBTSnoopEnabled(); |
|
} |
|
} |
|
|
|
private: |
|
BTStackLogConfig() |
|
: kBTSnoopEnableProperty_("persist.bluetooth.btsnoopenable"), |
|
kBTSnoopShouldSaveLastProperty_("persist.bluetooth.btsnoopsavelast"), |
|
kBTForceTurnOffInboundDataMonitorProperty_("persist.bluetooth.offmonitor") {} |
|
|
|
bool isPropertySet(const std::string& key) const { |
|
char value[PROPERTY_VALUE_MAX] = {0}; |
|
if (osi_property_get(key.c_str(), value, "")) { |
|
return true; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
bool IsBTSnoopFeatureEnabled(const char* key) const { |
|
char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0}; |
|
osi_property_get(key, btsnoop_enabled, "false"); |
|
return std::string(btsnoop_enabled) == std::string("true"); |
|
} |
|
|
|
friend class Singleton<BTStackLogConfig>; |
|
|
|
const std::string kBTSnoopEnableProperty_; |
|
const std::string kBTSnoopShouldSaveLastProperty_; |
|
const std::string kBTForceTurnOffInboundDataMonitorProperty_; |
|
}; |
|
|
|
class StackConfigImpl { |
|
public: |
|
StackConfigImpl() = default; |
|
~StackConfigImpl() = default; |
|
|
|
bool IsNeedOverWriteConfig() const { |
|
return BTStackLogConfig::GetInstance()->IsNeedOverWriteConfig(); |
|
} |
|
|
|
config_t* OverwriteConfig(config_t* config) { |
|
std::unique_ptr<StackConfigParser> config_parse(new StackConfigParser); |
|
return config_parse->OverwriteConfig(config); |
|
} |
|
|
|
const std::shared_ptr<ControllerLogModeParser> LoadFWLogModeParser( |
|
TraceLevel level) { |
|
return ControllerLogModeFactory::GetInstance()->Create(level); |
|
} |
|
|
|
std::vector<uint8_t> GetFWLogEnableCommandPacket( |
|
const std::shared_ptr<ControllerLogModeParser>& parser) { |
|
return parser->GetEnableCommandPacket(); |
|
} |
|
|
|
std::vector<uint8_t> GetFWLogFilterommandPacket( |
|
const std::shared_ptr<ControllerLogModeParser>& parser) { |
|
return parser->GetFilterommandPacket(); |
|
} |
|
|
|
bool IsBTSnoopEnabled() const { |
|
return BTStackLogConfig::GetInstance()->IsBTSnoopEnabled(); |
|
} |
|
|
|
bool IsBTSnoopSaveLastEnabled() const { |
|
return BTStackLogConfig::GetInstance()->IsBTSnoopSaveLastEnabled(); |
|
} |
|
|
|
bool IsInboundDataMonitorEnabled() const { |
|
return BTStackLogConfig::GetInstance()->IsInboundDataMonitorEnabled(); |
|
} |
|
}; |
|
|
|
StackConfig::StackConfig() : config_impl_(new StackConfigImpl()) {} |
|
|
|
StackConfig* StackConfig::GetInstance() { |
|
return base::Singleton<StackConfig>::get(); |
|
} |
|
|
|
bool StackConfig::IsNeedOverWriteConfig() const { |
|
return config_impl_->IsNeedOverWriteConfig(); |
|
} |
|
|
|
config_t* StackConfig::OverwriteConfig(config_t* config) { |
|
return config_impl_->OverwriteConfig(config); |
|
} |
|
|
|
const std::shared_ptr<ControllerLogModeParser> StackConfig::LoadFWLogModeParser( |
|
TraceLevel level) { |
|
return config_impl_->LoadFWLogModeParser(level); |
|
} |
|
|
|
std::vector<uint8_t> StackConfig::GetFWLogEnableCommandPacket( |
|
const std::shared_ptr<ControllerLogModeParser>& parser) { |
|
return config_impl_->GetFWLogEnableCommandPacket(parser); |
|
} |
|
|
|
std::vector<uint8_t> StackConfig::GetFWLogFilterommandPacket( |
|
const std::shared_ptr<ControllerLogModeParser>& parser) { |
|
return config_impl_->GetFWLogFilterommandPacket(parser); |
|
} |
|
|
|
bool StackConfig::IsBTSnoopEnabled() const { |
|
return config_impl_->IsBTSnoopEnabled(); |
|
} |
|
|
|
bool StackConfig::IsBTSnoopSaveLastEnabled() const { |
|
return config_impl_->IsBTSnoopSaveLastEnabled(); |
|
} |
|
|
|
bool StackConfig::IsInboundDataMonitorEnabled() const { |
|
return config_impl_->IsInboundDataMonitorEnabled(); |
|
} |
|
|
|
} // namespace stack |
|
} // namespace bluetooth |
|
} // namespace mediatek |
|
} // namespace vendor
|
|
|