From: Lukas0610 Date: Tue, 6 Nov 2018 14:17:59 +0000 (+0100) Subject: universal7580: add device-specific bluetooth HIDL implementation X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=8d217709c58171d271624fdb749fd526ce606688;p=GitHub%2FLineageOS%2Fandroid_device_samsung_universal7580-common.git universal7580: add device-specific bluetooth HIDL implementation Change-Id: I0a239cfd728fe3fcee4bbbb7f557becad666935a --- diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..80a7ca9 --- /dev/null +++ b/Android.bp @@ -0,0 +1,3 @@ +subdirs = [ + "hardware", +] diff --git a/device-common.mk b/device-common.mk index 73fd8e8..78aae93 100644 --- a/device-common.mk +++ b/device-common.mk @@ -34,7 +34,7 @@ PRODUCT_COPY_FILES += \ # Bluetooth PRODUCT_PACKAGES += \ - android.hardware.bluetooth@1.0-impl \ + android.hardware.bluetooth@1.0-impl.7580 \ libbt-vendor # Camera diff --git a/hardware/Android.bp b/hardware/Android.bp new file mode 100644 index 0000000..0d0122b --- /dev/null +++ b/hardware/Android.bp @@ -0,0 +1,3 @@ +subdirs = [ + "bluetooth", +] diff --git a/hardware/bluetooth/Android.bp b/hardware/bluetooth/Android.bp new file mode 100644 index 0000000..feb2ce2 --- /dev/null +++ b/hardware/bluetooth/Android.bp @@ -0,0 +1,41 @@ +// +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "android.hardware.bluetooth@1.0-impl.7580", + defaults: ["hidl_defaults"], + vendor: true, + relative_install_path: "hw", + srcs: [ + "bluetooth_hci.cc", + "bluetooth_address.cc", + "vendor_interface.cc", + ], + shared_libs: [ + "android.hardware.bluetooth@1.0", + "libbase", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + static_libs: [ + "android.hardware.bluetooth-async", + "android.hardware.bluetooth-hci", + ], +} + diff --git a/hardware/bluetooth/OWNERS b/hardware/bluetooth/OWNERS new file mode 100644 index 0000000..5df5bfe --- /dev/null +++ b/hardware/bluetooth/OWNERS @@ -0,0 +1,3 @@ +eisenbach@google.com +mylesgw@google.com +pavlin@google.com diff --git a/hardware/bluetooth/bluetooth_address.cc b/hardware/bluetooth/bluetooth_address.cc new file mode 100644 index 0000000..93a5469 --- /dev/null +++ b/hardware/bluetooth/bluetooth_address.cc @@ -0,0 +1,97 @@ +// +// Copyright 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "bluetooth_address.h" + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +void BluetoothAddress::bytes_to_string(const uint8_t* addr, char* addr_str) { + sprintf(addr_str, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); +} + +bool BluetoothAddress::string_to_bytes(const char* addr_str, uint8_t* addr) { + if (addr_str == NULL) return false; + if (strnlen(addr_str, kStringLength) != kStringLength) return false; + unsigned char trailing_char = '\0'; + + return (sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx%1c", + &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5], + &trailing_char) == kBytes); +} + +bool BluetoothAddress::get_local_address(uint8_t* local_addr) { + char property[PROPERTY_VALUE_MAX] = {0}; + + // Get local bdaddr storage path from a system property. + if (property_get(PROPERTY_BT_BDADDR_PATH, property, NULL)) { + ALOGD("%s: Trying %s", __func__, property); + + int addr_fd = open(property, O_RDONLY); + if (addr_fd != -1) { + char address[kStringLength + 1] = {0}; + int bytes_read = read(addr_fd, address, kStringLength); + if (bytes_read == -1) { + ALOGE("%s: Error reading address from %s: %s", __func__, property, + strerror(errno)); + } + close(addr_fd); + + // Null terminate the string. + address[kStringLength] = '\0'; + + // If the address is not all zeros, then use it. + const uint8_t zero_bdaddr[kBytes] = {0, 0, 0, 0, 0, 0}; + if ((string_to_bytes(address, local_addr)) && + (memcmp(local_addr, zero_bdaddr, kBytes) != 0)) { + ALOGD("%s: Got Factory BDA %s", __func__, address); + return true; + } else { + ALOGE("%s: Got Invalid BDA '%s' from %s", __func__, address, property); + } + } + } + + // No BDADDR found in the file. Look for BDA in a factory property. + if (property_get(FACTORY_BDADDR_PROPERTY, property, NULL) && + string_to_bytes(property, local_addr)) { + return true; + } + + // No factory BDADDR found. Look for a previously stored BDA. + if (property_get(PERSIST_BDADDR_PROPERTY, property, NULL) && + string_to_bytes(property, local_addr)) { + return true; + } + + return false; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/hardware/bluetooth/bluetooth_address.h b/hardware/bluetooth/bluetooth_address.h new file mode 100644 index 0000000..94bf616 --- /dev/null +++ b/hardware/bluetooth/bluetooth_address.h @@ -0,0 +1,61 @@ +// +// Copyright 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#pragma once + +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +// The property key stores the storage location of Bluetooth Device Address +static constexpr char PROPERTY_BT_BDADDR_PATH[] = "ro.bt.bdaddr_path"; + +// Check for a legacy address stored as a property. +static constexpr char PERSIST_BDADDR_PROPERTY[] = + "persist.service.bdroid.bdaddr"; + +// If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH and there +// is no available persistent bdaddr available from PERSIST_BDADDR_PROPERTY, +// use a factory set address. +static constexpr char FACTORY_BDADDR_PROPERTY[] = "ro.boot.btmacaddr"; + +// Encapsulate handling for Bluetooth Addresses: +class BluetoothAddress { + public: + // Conversion constants + static constexpr size_t kStringLength = sizeof("XX:XX:XX:XX:XX:XX") - 1; + static constexpr size_t kBytes = (kStringLength + 1) / 3; + + static void bytes_to_string(const uint8_t* addr, char* addr_str); + + static bool string_to_bytes(const char* addr_str, uint8_t* addr); + + static bool get_local_address(uint8_t* addr); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/hardware/bluetooth/bluetooth_hci.cc b/hardware/bluetooth/bluetooth_hci.cc new file mode 100644 index 0000000..e14e3d7 --- /dev/null +++ b/hardware/bluetooth/bluetooth_hci.cc @@ -0,0 +1,145 @@ +// +// Copyright 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#define LOG_TAG "android.hardware.bluetooth@1.0-impl" +#include "bluetooth_hci.h" + +#include + +#include "vendor_interface.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +static const uint8_t HCI_DATA_TYPE_COMMAND = 1; +static const uint8_t HCI_DATA_TYPE_ACL = 2; +static const uint8_t HCI_DATA_TYPE_SCO = 3; + +class BluetoothDeathRecipient : public hidl_death_recipient { + public: + BluetoothDeathRecipient(const sp hci) : mHci(hci) {} + + virtual void serviceDied( + uint64_t /*cookie*/, + const wp<::android::hidl::base::V1_0::IBase>& /*who*/) { + ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died"); + has_died_ = true; + mHci->close(); + } + sp mHci; + bool getHasDied() const { return has_died_; } + void setHasDied(bool has_died) { has_died_ = has_died; } + + private: + bool has_died_; +}; + +BluetoothHci::BluetoothHci() + : death_recipient_(new BluetoothDeathRecipient(this)) {} + +Return BluetoothHci::initialize( + const ::android::sp& cb) { + ALOGI("BluetoothHci::initialize()"); + if (cb == nullptr) { + ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)"); + return Void(); + } + + death_recipient_->setHasDied(false); + cb->linkToDeath(death_recipient_, 0); + + bool rc = VendorInterface::Initialize( + [cb](bool status) { + auto hidl_status = cb->initializationComplete( + status ? Status::SUCCESS : Status::INITIALIZATION_ERROR); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call initializationComplete()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->hciEventReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call hciEventReceived()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->aclDataReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call aclDataReceived()"); + } + }, + [cb](const hidl_vec& packet) { + auto hidl_status = cb->scoDataReceived(packet); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call scoDataReceived()"); + } + }); + if (!rc) { + auto hidl_status = cb->initializationComplete(Status::INITIALIZATION_ERROR); + if (!hidl_status.isOk()) { + ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)"); + } + } + + unlink_cb_ = [cb](sp& death_recipient) { + if (death_recipient->getHasDied()) + ALOGI("Skipping unlink call, service died."); + else + cb->unlinkToDeath(death_recipient); + }; + + return Void(); +} + +Return BluetoothHci::close() { + ALOGI("BluetoothHci::close()"); + unlink_cb_(death_recipient_); + VendorInterface::Shutdown(); + return Void(); +} + +Return BluetoothHci::sendHciCommand(const hidl_vec& command) { + sendDataToController(HCI_DATA_TYPE_COMMAND, command); + return Void(); +} + +Return BluetoothHci::sendAclData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_ACL, data); + return Void(); +} + +Return BluetoothHci::sendScoData(const hidl_vec& data) { + sendDataToController(HCI_DATA_TYPE_SCO, data); + return Void(); +} + +void BluetoothHci::sendDataToController(const uint8_t type, + const hidl_vec& data) { + VendorInterface::get()->Send(type, data.data(), data.size()); +} + +IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) { + return new BluetoothHci(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/hardware/bluetooth/bluetooth_hci.h b/hardware/bluetooth/bluetooth_hci.h new file mode 100644 index 0000000..e2797b1 --- /dev/null +++ b/hardware/bluetooth/bluetooth_hci.h @@ -0,0 +1,61 @@ +// +// Copyright 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_ +#define HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_ + +#include + +#include + +#include + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::Return; +using ::android::hardware::hidl_vec; + +class BluetoothDeathRecipient; + +class BluetoothHci : public IBluetoothHci { + public: + BluetoothHci(); + Return initialize( + const ::android::sp& cb) override; + Return sendHciCommand(const hidl_vec& packet) override; + Return sendAclData(const hidl_vec& data) override; + Return sendScoData(const hidl_vec& data) override; + Return close() override; + + private: + void sendDataToController(const uint8_t type, const hidl_vec& data); + ::android::sp death_recipient_; + std::function&)> unlink_cb_; +}; + +extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_ diff --git a/hardware/bluetooth/vendor_interface.cc b/hardware/bluetooth/vendor_interface.cc new file mode 100644 index 0000000..a8f5bb4 --- /dev/null +++ b/hardware/bluetooth/vendor_interface.cc @@ -0,0 +1,385 @@ +// +// Copyright 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "vendor_interface.h" + +#define LOG_TAG "android.hardware.bluetooth@1.0-impl" +#include +#include + +#include +#include + +#include "bluetooth_address.h" +#include "h4_protocol.h" +#include "mct_protocol.h" + +static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so"; +static const char* VENDOR_LIBRARY_SYMBOL_NAME = + "BLUETOOTH_VENDOR_LIB_INTERFACE"; + +static const int INVALID_FD = -1; + +namespace { + +using android::hardware::bluetooth::V1_0::implementation::VendorInterface; +using android::hardware::hidl_vec; + +struct { + tINT_CMD_CBACK cb; + uint16_t opcode; +} internal_command; + +// True when LPM is not enabled yet or wake is not asserted. +bool lpm_wake_deasserted; +uint32_t lpm_timeout_ms; +bool recent_activity_flag; + +VendorInterface* g_vendor_interface = nullptr; +std::mutex wakeup_mutex_; + +HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec& data) { + size_t packet_size = data.size() + sizeof(HC_BT_HDR); + HC_BT_HDR* packet = reinterpret_cast(new uint8_t[packet_size]); + packet->offset = 0; + packet->len = data.size(); + packet->layer_specific = 0; + packet->event = event; + // TODO(eisenbach): Avoid copy here; if BT_HDR->data can be ensured to + // be the only way the data is accessed, a pointer could be passed here... + memcpy(packet->data, data.data(), data.size()); + return packet; +} + +bool internal_command_event_match(const hidl_vec& packet) { + uint8_t event_code = packet[0]; + if (event_code != HCI_COMMAND_COMPLETE_EVENT) { + ALOGE("%s: Unhandled event type %02X", __func__, event_code); + return false; + } + + size_t opcode_offset = HCI_EVENT_PREAMBLE_SIZE + 1; // Skip num packets. + + uint16_t opcode = packet[opcode_offset] | (packet[opcode_offset + 1] << 8); + + ALOGV("%s internal_command.opcode = %04X opcode = %04x", __func__, + internal_command.opcode, opcode); + return opcode == internal_command.opcode; +} + +uint8_t transmit_cb(uint16_t opcode, void* buffer, tINT_CMD_CBACK callback) { + ALOGV("%s opcode: 0x%04x, ptr: %p, cb: %p", __func__, opcode, buffer, + callback); + internal_command.cb = callback; + internal_command.opcode = opcode; + uint8_t type = HCI_PACKET_TYPE_COMMAND; + HC_BT_HDR* bt_hdr = reinterpret_cast(buffer); + VendorInterface::get()->Send(type, bt_hdr->data, bt_hdr->len); + delete[] reinterpret_cast(buffer); + return true; +} + +void firmware_config_cb(bt_vendor_op_result_t result) { + ALOGV("%s result: %d", __func__, result); + VendorInterface::get()->OnFirmwareConfigured(result); +} + +void sco_config_cb(bt_vendor_op_result_t result) { + ALOGD("%s result: %d", __func__, result); +} + +void low_power_mode_cb(bt_vendor_op_result_t result) { + ALOGD("%s result: %d", __func__, result); +} + +void sco_audiostate_cb(bt_vendor_op_result_t result) { + ALOGD("%s result: %d", __func__, result); +} + +void* buffer_alloc_cb(int size) { + void* p = new uint8_t[size]; + ALOGV("%s pts: %p, size: %d", __func__, p, size); + return p; +} + +void buffer_free_cb(void* buffer) { + ALOGV("%s ptr: %p", __func__, buffer); + delete[] reinterpret_cast(buffer); +} + +void epilog_cb(bt_vendor_op_result_t result) { + ALOGD("%s result: %d", __func__, result); +} + +void a2dp_offload_cb(bt_vendor_op_result_t result, bt_vendor_opcode_t op, + uint8_t av_handle) { + ALOGD("%s result: %d, op: %d, handle: %d", __func__, result, op, av_handle); +} + +const bt_vendor_callbacks_t lib_callbacks = { + sizeof(lib_callbacks), firmware_config_cb, sco_config_cb, + low_power_mode_cb, sco_audiostate_cb, buffer_alloc_cb, + buffer_free_cb, transmit_cb, epilog_cb, + a2dp_offload_cb}; + +} // namespace + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +class FirmwareStartupTimer { + public: + FirmwareStartupTimer() : start_time_(std::chrono::steady_clock::now()) {} + + ~FirmwareStartupTimer() { + std::chrono::duration duration = + std::chrono::steady_clock::now() - start_time_; + double s = duration.count(); + if (s == 0) return; + ALOGI("Firmware configured in %.3fs", s); + } + + private: + std::chrono::steady_clock::time_point start_time_; +}; + +bool VendorInterface::Initialize( + InitializeCompleteCallback initialize_complete_cb, + PacketReadCallback event_cb, PacketReadCallback acl_cb, + PacketReadCallback sco_cb) { + if (g_vendor_interface) { + ALOGE("%s: No previous Shutdown()?", __func__); + return false; + } + g_vendor_interface = new VendorInterface(); + return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb, + sco_cb); +} + +void VendorInterface::Shutdown() { + LOG_ALWAYS_FATAL_IF(!g_vendor_interface, "%s: No Vendor interface!", + __func__); + g_vendor_interface->Close(); + delete g_vendor_interface; + g_vendor_interface = nullptr; +} + +VendorInterface* VendorInterface::get() { return g_vendor_interface; } + +bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb, + PacketReadCallback event_cb, + PacketReadCallback acl_cb, + PacketReadCallback sco_cb) { + initialize_complete_cb_ = initialize_complete_cb; + + // Initialize vendor interface + + lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW); + if (!lib_handle_) { + ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME, + dlerror()); + return false; + } + + lib_interface_ = reinterpret_cast( + dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME)); + if (!lib_interface_) { + ALOGE("%s unable to find symbol %s in %s (%s)", __func__, + VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror()); + return false; + } + + // Get the local BD address + + uint8_t local_bda[BluetoothAddress::kBytes]; + if (!BluetoothAddress::get_local_address(local_bda)) { + LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__); + } + int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda); + if (status) { + ALOGE("%s unable to initialize vendor library: %d", __func__, status); + return false; + } + + ALOGD("%s vendor library loaded", __func__); + + // Power on the controller + + int power_state = BT_VND_PWR_ON; + lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state); + + // Get the UART socket(s) + + int fd_list[CH_MAX] = {0}; + int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list); + + if (fd_count < 1 || fd_count > CH_MAX - 1) { + ALOGE("%s: fd_count %d is invalid!", __func__, fd_count); + return false; + } + + for (int i = 0; i < fd_count; i++) { + if (fd_list[i] == INVALID_FD) { + ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]); + return false; + } + } + + event_cb_ = event_cb; + PacketReadCallback intercept_events = [this](const hidl_vec& event) { + HandleIncomingEvent(event); + }; + + if (fd_count == 1) { + hci::H4Protocol* h4_hci = + new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb); + fd_watcher_.WatchFdForNonBlockingReads( + fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); }); + hci_ = h4_hci; + } else { + hci::MctProtocol* mct_hci = + new hci::MctProtocol(fd_list, intercept_events, acl_cb); + fd_watcher_.WatchFdForNonBlockingReads( + fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); }); + fd_watcher_.WatchFdForNonBlockingReads( + fd_list[CH_ACL_IN], + [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); }); + hci_ = mct_hci; + } + + // Initially, the power management is off. + lpm_wake_deasserted = true; + + // Start configuring the firmware + firmware_startup_timer_ = new FirmwareStartupTimer(); + lib_interface_->op(BT_VND_OP_FW_CFG, nullptr); + + return true; +} + +void VendorInterface::Close() { + // These callbacks may send HCI events (vendor-dependent), so make sure to + // StopWatching the file descriptor after this. + if (lib_interface_ != nullptr) { + bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE; + lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode); + } + + fd_watcher_.StopWatchingFileDescriptors(); + + if (hci_ != nullptr) { + delete hci_; + hci_ = nullptr; + } + + if (lib_interface_ != nullptr) { + lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr); + + int power_state = BT_VND_PWR_OFF; + lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state); + + lib_interface_->cleanup(); + } + + if (lib_handle_ != nullptr) { + dlclose(lib_handle_); + lib_handle_ = nullptr; + } + + if (firmware_startup_timer_ != nullptr) { + delete firmware_startup_timer_; + firmware_startup_timer_ = nullptr; + } +} + +size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) { + std::unique_lock lock(wakeup_mutex_); + recent_activity_flag = true; + + if (lpm_wake_deasserted == true) { + // Restart the timer. + fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms), + [this]() { OnTimeout(); }); + // Assert wake. + lpm_wake_deasserted = false; + bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT; + lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState); + ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8)); + } + + return hci_->Send(type, data, length); +} + +void VendorInterface::OnFirmwareConfigured(uint8_t result) { + ALOGD("%s result: %d", __func__, result); + + if (firmware_startup_timer_ != nullptr) { + delete firmware_startup_timer_; + firmware_startup_timer_ = nullptr; + } + + if (initialize_complete_cb_ != nullptr) { + initialize_complete_cb_(result == 0); + initialize_complete_cb_ = nullptr; + } + + lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms); + ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms); + + bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE; + lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode); + + ALOGD("%s Calling StartLowPowerWatchdog()", __func__); + fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms), + [this]() { OnTimeout(); }); +} + +void VendorInterface::OnTimeout() { + ALOGV("%s", __func__); + std::unique_lock lock(wakeup_mutex_); + if (recent_activity_flag == false) { + lpm_wake_deasserted = true; + bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_DEASSERT; + lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState); + fd_watcher_.ConfigureTimeout(std::chrono::seconds(0), []() { + ALOGE("Zero timeout! Should never happen."); + }); + } + recent_activity_flag = false; +} + +void VendorInterface::HandleIncomingEvent(const hidl_vec& hci_packet) { + if (internal_command.cb != nullptr && + internal_command_event_match(hci_packet)) { + HC_BT_HDR* bt_hdr = WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet); + + // The callbacks can send new commands, so don't zero after calling. + tINT_CMD_CBACK saved_cb = internal_command.cb; + internal_command.cb = nullptr; + saved_cb(bt_hdr); + } else { + event_cb_(hci_packet); + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/hardware/bluetooth/vendor_interface.h b/hardware/bluetooth/vendor_interface.h new file mode 100644 index 0000000..a401ee6 --- /dev/null +++ b/hardware/bluetooth/vendor_interface.h @@ -0,0 +1,76 @@ +// +// Copyright 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#pragma once + +#include + +#include "async_fd_watcher.h" +#include "bt_vendor_lib.h" +#include "hci_protocol.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::hidl_vec; +using InitializeCompleteCallback = std::function; +using PacketReadCallback = std::function&)>; + +class FirmwareStartupTimer; + +class VendorInterface { + public: + static bool Initialize(InitializeCompleteCallback initialize_complete_cb, + PacketReadCallback event_cb, PacketReadCallback acl_cb, + PacketReadCallback sco_cb); + static void Shutdown(); + static VendorInterface *get(); + + size_t Send(uint8_t type, const uint8_t *data, size_t length); + + void OnFirmwareConfigured(uint8_t result); + + private: + virtual ~VendorInterface() = default; + + bool Open(InitializeCompleteCallback initialize_complete_cb, + PacketReadCallback event_cb, PacketReadCallback acl_cb, + PacketReadCallback sco_cb); + void Close(); + + void OnTimeout(); + + void HandleIncomingEvent(const hidl_vec& hci_packet); + + void *lib_handle_; + bt_vendor_interface_t *lib_interface_; + async::AsyncFdWatcher fd_watcher_; + InitializeCompleteCallback initialize_complete_cb_; + hci::HciProtocol* hci_; + + PacketReadCallback event_cb_; + + FirmwareStartupTimer *firmware_startup_timer_; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android