【android bluetooth 协议分析 02】【bluetooth hal 层详解 4】【高通蓝牙hal主要流程介绍-中】
1. 背景
本节主要讨论 高通 蓝牙 hal 中,的一些流程。 看看你是否都清楚如下问题:
- 高通芯片电如何控制?
- 串口是在哪里控制的?
- 固件如何下载?
- 初始化流程是怎么样的?
如果你已经对上述讨论的问题,已经很清楚了,那你无需阅读该文章,请自行忽略。当然,也可以给笨叔挑挑错。 欢迎评论,一起探讨,毕竟都是笨叔自己的理解,难免有点出入,我也想进步!!!
阅读 本篇内容前, 请先阅读 【android bluetooth 协议分析 02】【bluetooth hal 层详解 3】【高通蓝牙hal主要流程介绍-上】
我们继续接着 上篇 3.3.3 小节,讲解。
【android bluetooth 协议分析 02】【bluetooth hal 层详解 3】【高通蓝牙hal主要流程介绍-上】3.3.3 调用 controller_->Init 函数
// hidl_hci/1.0/default/uart_controller.cpp
bool UartController::Init(PacketReadCallback pkt_read_cb)
{power_manager_.Init(soc_type_);// 1. 给芯片 上电if (soc_need_reload_patch) {// power off the chip firstpower_manager_.SetPower(false);// power on the chip using power managerpower_manager_.SetPower(true);}// 2. 初始化 HciTransporthci_transport_ = static_cast<HciTransport*> (uart_transport);ret = uart_transport->Init(soc_type_, soc_need_reload_patch);// 3. 创建 固件 补丁管理器patch_dl_manager = new (std::nothrow)PatchDLManager(soc_type_, uart_transport, &power_manager_);uart_transport->ClockOperation(USERIAL_OP_CLK_ON);//Download the NVM/RAM patchif (soc_need_reload_patch) {logger_->PropertyGet("vendor.wc_transport.skip_patch_dload", skip_patch_download, "false");if (strcmp(skip_patch_download, "true") != 0) {// 4. 开始打补丁, 下载固件if (patch_dl_manager->PerformChipInit() < 0) {}temp_add_on_features = patch_dl_manager->GetAddOnFeatureList();} else {}}// 获取 controller 的芯片版本, 做记录使用chipset_ver_ = patch_dl_manager->GetChipVersion();init_done_ = true;ALOGD("Init succeded");return init_done_;
}
将上面的操作总结为如下:
- 给芯片 上电
- 初始化 HciTransport
- 开始打补丁, 下载固件
下面分别展开讲解
2. 芯片上电
UartController::PowerManager power_manager_;
power_manager_ 是一个变量,并不是一个指针。他伴随着 UartController 对象的创建而创建。
芯片上电主要调用如下步骤:
power_manager_.Init(soc_type_);power_manager_.SetPower(false);power_manager_.SetPower(true);
1. PowerManager :: Init
void PowerManager :: Init(BluetoothSocType soc_type)
{if (pm_state_ != POWER_MANAGER_OFF)return;bt_soc_type_ = soc_type;
}
这里仅仅是保存了当前 芯片soc 的类型。 我们这里的类型通过如下两个属性获得。
# bt0
persist.vendor.qcom.bluetooth.soc# bt1
persist.vendor.qcom.bluetooth.soc1
bt0 :hastings
bt1: rome
2. PowerManager :: SetPower
bool SetPower(bool enable, bool retentionMode = false);// 默认 retentionMode = falsebool PowerManager :: SetPower(bool enable, bool retentionMode)
{bool ret = false;ALOGD("%s: enable: %x", __func__, enable);switch (bt_soc_type_) {int rfkill_fd;case BT_SOC_ROME:case BT_SOC_HASTINGS:// 1.获取 rfkill_fdrfkill_fd = GetRfkillFd();if (rfkill_fd < 0)return false;// 2. 通过 rfkill 去控制电ret = ControlRfkill(rfkill_fd, enable);close(rfkill_fd);break;}return ret;
}
这里我只保留了最重要的code. 我们芯片类型是 BT_SOC_HASTINGS 和 BT_SOC_ROME
这里看到直接调用了 rfkill 相关的内容
1. PowerManager :: GetRfkillFd
int PowerManager :: GetRfkillFd()
{int rfkill_fd;rfkill_fd = InitializeRfkill();return rfkill_fd;
}
#define BT_RFKILL_NAME "bt_power"
#define BT_RFKILL1_NAME "bt_power_new"const char* Util::getBtRfkillName()
{return isHwSlot1() ? BT_RFKILL1_NAME : BT_RFKILL_NAME;
}#define RFKILL_STATE_PATH "/sys/class/rfkill/rfkill%d/state"
#define RFKILL_TYPE_PATH "/sys/class/rfkill/rfkill%d/type"
#define RFKILL_NAME_PATH "/sys/class/rfkill/rfkill%d/name"#define BT_RFKILL_TYPE "bluetooth"int PowerManager :: InitializeRfkill()
{int fd;char rfkill_type[64] = {'\0'}, rfkill_name[64] = {'\0'}, rfkill_state[64] = {'\0'};/* 枚举所有 rfkill 设备,找到和蓝牙相关的 */for (int i = 0; rfkill_id_ == -1; i++) {/* 根据 i: 去拼接字符串:1. /sys/class/rfkill/rfkill0/type2. /sys/class/rfkill/rfkill0/name*/snprintf(rfkill_type, sizeof(rfkill_type), (char *)RFKILL_TYPE_PATH, i);snprintf(rfkill_name, sizeof(rfkill_name), (char *)RFKILL_NAME_PATH, i);// 如果 type 和 name 文件不存在直接跳过if (!Util::fileExist(rfkill_type) ||!Util::fileExist(rfkill_name)) {break;}/* 如果 (cat /sys/class/rfkill/rfkill0/type) == (bluetooth) 并且(cat /sys/class/rfkill/rfkill0/name) == bt0(bt_power) == bt1(bt_power_new)说明已经找到了对应的蓝牙 rfkill 节点*/if (Util::fileContainString(rfkill_type, BT_RFKILL_TYPE) &&Util::fileContainString(rfkill_name, Util::getBtRfkillName())) {rfkill_id_ = i;break;}}if (rfkill_id_ == -1) {/* rfkill device not found, return */return -1;}// 这里拼接出, 我们操作的节点: /sys/class/rfkill/rfkill0/statesnprintf(rfkill_state, sizeof(rfkill_state), (char *)RFKILL_STATE_PATH, rfkill_id_);// 打开 /sys/class/rfkill/rfkill0/state 节点fd = open(rfkill_state, O_RDWR);if (fd < 0)ALOGE("open(%s) for write failed: %s (%d)", rfkill_state, strerror(errno), errno);return fd;
}
- 通过 对 PowerManager :: InitializeRfkill 分析我们可以知道,我们蓝牙的电 是通过 操作 /sys/class/rfkill/rfkill0/state 节点
2. PowerManager :: ControlRfkill
bool PowerManager :: ControlRfkill(int rfkill_fd, bool enable)
{char power_on = enable ? '1' : '0';ALOGD("%s: rfkill_fd: %d, enable: %x", __func__, rfkill_fd, enable);if (write(rfkill_fd, &power_on, 1) < 0) {ALOGE("%s: write rfkill failed: %s (%d)", __func__, strerror(errno), errno);Cleanup(rfkill_fd);return false;}return true;
}
- 通过 向 /sys/class/rfkill/rfkill0/state 节点 写1 上电, 写0 下电。
这里就算回答清楚了 开篇提到的,高通芯片电如何控制?
3. 初始化 HciTransport
接下来我们来看一下 uart_transport 中有干了那些不为认知的事情。
// 1. 创建一个 HciUartTransport 对象, HciUartTransport 继承于 HciTransportuart_transport = new (std::nothrow)HciUartTransport(health_info)hci_transport_ = static_cast<HciTransport*> (uart_transport);// 2. 调用 HciUartTransport->Initret = uart_transport->Init(soc_type_, soc_need_reload_patch);
1. 创建 HciUartTransport 对象
class HciUartTransport : public HciTransport {HciUartTransport(HealthInfoLog* theHealthInfo) {ctrl_fd_ = -1;data_fd_ = -1;health_info = theHealthInfo;Util::getUartDevice(uart_device_);};}
#define BT_HIDL_UART_PROP "persist.vendor.bt.hidl.uart"
#define BT_HIDL1_UART_PROP "persist.vendor.bt.hidl1.uart"#define UART_DEVICE "/dev/ttyHS0"
#define UART1_DEVICE "/dev/ttyHS2"int Util::getHwSlot()
{return hw_slot_;
}bool Util::getUartDevice(char *device)
{return getUartDevice(getHwSlot(), device);
}bool Util::getUartDevice(int slot, char *device)
{if (!device)return false;switch (slot) {// 根据不同的 slot, 来区分 bt0, bt1case BLUETOOTH_SLOT_0: {/*如果 persist.vendor.bt.hidl.uart 属性中没有指定 串口,那就使用默认的串口 /dev/ttyHS0*/property_get(BT_HIDL_UART_PROP, device, UART_DEVICE);return true;}case BLUETOOTH_SLOT_1: {/*如果 persist.vendor.bt.hidl1.uart 属性中没有指定 串口,那就使用默认的串口 /dev/ttyHS2*/property_get(BT_HIDL1_UART_PROP, device, UART1_DEVICE);return true;}default: {/* Invalid Bluetooth slot */return false;}}
}
bt0 和 bt1 串口 可以使用默认的配置, 同时也可以通过系统属性来配置。这里可以根据不同的项目。灵活配置。
会将 串口设备最终保存在 HciUartTransport::uart_device_ 变量中。
2. HciUartTransport::Init
ret = uart_transport->Init(soc_type_, soc_need_reload_patch);
bool HciUartTransport::Init(BluetoothSocType soc_type, bool need_reload)
{switch (soc_type) {case BT_SOC_HASTINGS:case BT_SOC_MOSELLE:case BT_SOC_HAMILTON:status = InitTransport(&normal_cfg);break;default: {ALOGE("Unknown chip type: %d", soc_type);}}return status;
}
// private functions
bool HciUartTransport::InitTransport(tUSERIAL_CFG *p_cfg)
{ALOGI("%s: opening %s", __func__, uart_device_);// 这里就会去 打开我们的串口。if ((ctrl_fd_ = open(uart_device_, O_RDWR | O_NOCTTY)) == -1) {ALOGE("%s: unable to open %s: %s(%d)", __func__, uart_device_,strerror(errno), errno);return false;}return true;
}
在 HciUartTransport::InitTransport 中涉及到 串口波特率 流控, 的初始化。 这里不在讨论。
看到这里,你是否对, 该问题: 串口是在哪里控制的?有答案了
4. 打补丁,下载固件
这个下篇 中介绍