diff options
author | Myles Watson <mylesgw@google.com> | 2017-02-09 16:47:33 -0800 |
---|---|---|
committer | Myles Watson <mylesgw@google.com> | 2017-02-23 15:44:04 -0800 |
commit | 90ee15b058f190426e99d652b428e370ed559cb7 (patch) | |
tree | ea937d3d94203944ef0ebf5c3b49f18eacb0473e /bluetooth | |
parent | a0499690e0b21e8857d4442c5e4838b66d82f275 (diff) | |
download | hikey-90ee15b058f190426e99d652b428e370ed559cb7.tar.gz |
hikey: Add a HIDL HAL for Bluetooth
The hikey HCI tty driver needs FIONREAD to be called before every read.
Add an HciPacketizerHikey class to make sure that FIONREAD is called.
Test: Bluetooth starts/stops, VtsHalBluetoothV1_0TargetTest passes
Change-Id: I9e9260337108c93cae66b89e21c3561916f42f54
Diffstat (limited to 'bluetooth')
-rw-r--r-- | bluetooth/Android.bp | 41 | ||||
-rw-r--r-- | bluetooth/android.hardware.bluetooth@1.0-service.hikey.rc | 4 | ||||
-rw-r--r-- | bluetooth/bluetooth_hci.cc | 152 | ||||
-rw-r--r-- | bluetooth/bluetooth_hci.h | 63 | ||||
-rw-r--r-- | bluetooth/hci_packetizer_hikey.cc | 121 | ||||
-rw-r--r-- | bluetooth/hci_packetizer_hikey.h | 38 | ||||
-rw-r--r-- | bluetooth/service.cc | 36 |
7 files changed, 455 insertions, 0 deletions
diff --git a/bluetooth/Android.bp b/bluetooth/Android.bp new file mode 100644 index 00000000..aecdcb7e --- /dev/null +++ b/bluetooth/Android.bp @@ -0,0 +1,41 @@ +// +// Copyright (C) 2017 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_binary { + name: "android.hardware.bluetooth@1.0-service.hikey", + proprietary: true, + relative_install_path: "hw", + srcs: [ + "bluetooth_hci.cc", + "hci_packetizer_hikey.cc", + "service.cc", + ], + shared_libs: [ + "android.hardware.bluetooth@1.0", + "libbase", + "libcutils", + "libhardware", + "libhwbinder", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], + static_libs: [ + "android.hardware.bluetooth-async", + "android.hardware.bluetooth-hci", + ], + init_rc: ["android.hardware.bluetooth@1.0-service.hikey.rc"], +} diff --git a/bluetooth/android.hardware.bluetooth@1.0-service.hikey.rc b/bluetooth/android.hardware.bluetooth@1.0-service.hikey.rc new file mode 100644 index 00000000..6f31efdf --- /dev/null +++ b/bluetooth/android.hardware.bluetooth@1.0-service.hikey.rc @@ -0,0 +1,4 @@ +service bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.hikey + class hal + user bluetooth + group bluetooth diff --git a/bluetooth/bluetooth_hci.cc b/bluetooth/bluetooth_hci.cc new file mode 100644 index 00000000..64107656 --- /dev/null +++ b/bluetooth/bluetooth_hci.cc @@ -0,0 +1,152 @@ +// +// 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.hikey" + +#include "bluetooth_hci.h" + +#include <utils/Log.h> + +#include <android-base/logging.h> + +#include "hci_internals.h" + +namespace { + +using android::hardware::bluetooth::V1_0::hikey::BluetoothHci; +using android::hardware::hidl_vec; + +BluetoothHci* g_bluetooth_hci = nullptr; + +size_t write_safely(int fd, const uint8_t* data, size_t length) { + size_t transmitted_length = 0; + while (length > 0) { + ssize_t ret = + TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length)); + + if (ret == -1) { + if (errno == EAGAIN) continue; + ALOGE("%s error writing to UART (%s)", __func__, strerror(errno)); + break; + + } else if (ret == 0) { + // Nothing written :( + ALOGE("%s zero bytes written - something went wrong...", __func__); + break; + } + + transmitted_length += ret; + length -= ret; + } + + return transmitted_length; +} + +} // namespace + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace hikey { + +Return<void> BluetoothHci::initialize( + const ::android::sp<IBluetoothHciCallbacks>& cb) { + ALOGI("BluetoothHci::initialize()"); + + CHECK(cb != nullptr); + event_cb_ = cb; + + hci_tty_fd_ = open("/dev/hci_tty", O_RDWR); + if (hci_tty_fd_ < 0) { + ALOGE("%s: Can't open hci_tty", __func__); + event_cb_->initializationComplete(Status::INITIALIZATION_ERROR); + } + + CHECK(g_bluetooth_hci == nullptr) << __func__ << " is not reentrant"; + g_bluetooth_hci = this; + + fd_watcher_.WatchFdForNonBlockingReads( + hci_tty_fd_, [this](int fd) { hci_packetizer_.OnDataReadyHikey(fd); }); + + event_cb_->initializationComplete(Status::SUCCESS); + return Void(); +} + +Return<void> BluetoothHci::close() { + ALOGW("BluetoothHci::close()"); + ::close(hci_tty_fd_); + hci_tty_fd_ = -1; + g_bluetooth_hci = nullptr; + return Void(); +} + +Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& packet) { + uint8_t type = HCI_PACKET_TYPE_COMMAND; + int rv = write_safely(hci_tty_fd_, &type, sizeof(type)); + if (rv == sizeof(type)) + rv = write_safely(hci_tty_fd_, packet.data(), packet.size()); + return Void(); +} + +Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& packet) { + uint8_t type = HCI_PACKET_TYPE_ACL_DATA; + int rv = write_safely(hci_tty_fd_, &type, sizeof(type)); + if (rv == sizeof(type)) + rv = write_safely(hci_tty_fd_, packet.data(), packet.size()); + return Void(); +} + +Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& packet) { + uint8_t type = HCI_PACKET_TYPE_SCO_DATA; + int rv = write_safely(hci_tty_fd_, &type, sizeof(type)); + if (rv == sizeof(type)) + rv = write_safely(hci_tty_fd_, packet.data(), packet.size()); + return Void(); +} + +BluetoothHci* BluetoothHci::get() { return g_bluetooth_hci; } + +void BluetoothHci::OnPacketReady() { + BluetoothHci::get()->HandleIncomingPacket(); +} + +void BluetoothHci::HandleIncomingPacket() { + HciPacketType hci_packet_type = hci_packetizer_.GetPacketType(); + hidl_vec<uint8_t> hci_packet = hci_packetizer_.GetPacket(); + + switch (hci_packet_type) { + case HCI_PACKET_TYPE_EVENT: + event_cb_->hciEventReceived(hci_packet); + break; + case HCI_PACKET_TYPE_ACL_DATA: + event_cb_->aclDataReceived(hci_packet); + break; + case HCI_PACKET_TYPE_SCO_DATA: + event_cb_->scoDataReceived(hci_packet); + break; + default: { + bool hci_packet_type_corrupted = true; + CHECK(hci_packet_type_corrupted == false); + } + } +} + +} // namespace hikey +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/bluetooth_hci.h b/bluetooth/bluetooth_hci.h new file mode 100644 index 00000000..91fad272 --- /dev/null +++ b/bluetooth/bluetooth_hci.h @@ -0,0 +1,63 @@ +// +// Copyright 2017 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 <android/hardware/bluetooth/1.0/IBluetoothHci.h> + +#include <hidl/MQDescriptor.h> + +#include "async_fd_watcher.h" +#include "hci_packetizer_hikey.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace hikey { + +using ::android::hardware::Return; +using ::android::hardware::hidl_vec; + +class BluetoothHci : public IBluetoothHci { + public: + Return<void> initialize( + const ::android::sp<IBluetoothHciCallbacks>& cb) override; + Return<void> sendHciCommand(const hidl_vec<uint8_t>& packet) override; + Return<void> sendAclData(const hidl_vec<uint8_t>& packet) override; + Return<void> sendScoData(const hidl_vec<uint8_t>& packet) override; + Return<void> close() override; + + static void OnPacketReady(); + + static BluetoothHci* get(); + + private: + ::android::sp<IBluetoothHciCallbacks> event_cb_; + int hci_tty_fd_; + + void HandleIncomingPacket(); + + async::AsyncFdWatcher fd_watcher_; + + HciPacketizerHikey hci_packetizer_{BluetoothHci::OnPacketReady}; +}; + +} // namespace hikey +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/hci_packetizer_hikey.cc b/bluetooth/hci_packetizer_hikey.cc new file mode 100644 index 00000000..9b54b8e0 --- /dev/null +++ b/bluetooth/hci_packetizer_hikey.cc @@ -0,0 +1,121 @@ +// +// Copyright 2017 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 "hci_packetizer_hikey.h" + +#include <sys/ioctl.h> +#include <utils/Log.h> + +#include <android-base/logging.h> + +namespace { + +const size_t preamble_size_for_type[] = { + 0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE, + HCI_EVENT_PREAMBLE_SIZE}; +const size_t packet_length_offset_for_type[] = { + 0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO, + HCI_LENGTH_OFFSET_EVT}; + +size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) { + size_t offset = packet_length_offset_for_type[type]; + if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset]; + return (((preamble[offset + 1]) << 8) | preamble[offset]); +} + +} // namespace + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace hikey { + +void HciPacketizerHikey::OnDataReadyHikey(int fd) { + int tty_bytes = 0; + if (ioctl(fd, FIONREAD, &tty_bytes) == -1) + ALOGE("%s:FIONREAD %s", __func__, strerror(errno)); + ALOGV("%s:tty_bytes = %d", __func__, tty_bytes); + uint8_t* tmp_buffer = new uint8_t[tty_bytes]; + size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, tmp_buffer, tty_bytes)); + CHECK(static_cast<int>(bytes_read) == tty_bytes); + + size_t index = 0; + while (index < bytes_read - 1) { + switch (hci_parser_state_) { + case HCI_IDLE: { + hci_packet_type_ = static_cast<HciPacketType>(tmp_buffer[index++]); + CHECK(hci_packet_type_ >= HCI_PACKET_TYPE_ACL_DATA && + hci_packet_type_ <= HCI_PACKET_TYPE_EVENT) + << "hci_packet_type_ = " + << static_cast<unsigned int>(hci_packet_type_); + hci_parser_state_ = HCI_TYPE_READY; + hci_packet_bytes_remaining_ = preamble_size_for_type[hci_packet_type_]; + hci_packet_bytes_read_ = 0; + break; + } + + case HCI_TYPE_READY: { + size_t bytes_to_copy = (bytes_read - index < hci_packet_bytes_remaining_ + ? bytes_read - index + : hci_packet_bytes_remaining_); + memcpy(hci_packet_preamble_ + hci_packet_bytes_read_, + &tmp_buffer[index], bytes_to_copy); + hci_packet_bytes_remaining_ -= bytes_to_copy; + hci_packet_bytes_read_ += bytes_to_copy; + index += bytes_to_copy; + ALOGV("%s:TYPE index = %d", __func__, static_cast<int>(index)); + if (hci_packet_bytes_remaining_ == 0) { + size_t packet_length = + HciGetPacketLengthForType(hci_packet_type_, hci_packet_preamble_); + hci_packet_.resize(preamble_size_for_type[hci_packet_type_] + + packet_length); + memcpy(hci_packet_.data(), hci_packet_preamble_, + preamble_size_for_type[hci_packet_type_]); + hci_packet_bytes_remaining_ = packet_length; + hci_parser_state_ = HCI_PAYLOAD; + hci_packet_bytes_read_ = 0; + } + break; + } + + case HCI_PAYLOAD: { + size_t bytes_to_copy = (bytes_read - index < hci_packet_bytes_remaining_ + ? bytes_read - index + : hci_packet_bytes_remaining_); + memcpy(hci_packet_.data() + preamble_size_for_type[hci_packet_type_] + + hci_packet_bytes_read_, + &tmp_buffer[index], bytes_to_copy); + hci_packet_bytes_remaining_ -= bytes_to_copy; + hci_packet_bytes_read_ += bytes_to_copy; + index += bytes_to_copy; + ALOGV("%s:PAYLOAD index = %d", __func__, static_cast<int>(index)); + if (hci_packet_bytes_remaining_ == 0) { + hci_packet_ready_cb_(); + hci_parser_state_ = HCI_IDLE; + } + break; + } + } + } + delete[] tmp_buffer; +} + +} // namespace hikey +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/hci_packetizer_hikey.h b/bluetooth/hci_packetizer_hikey.h new file mode 100644 index 00000000..12fdde28 --- /dev/null +++ b/bluetooth/hci_packetizer_hikey.h @@ -0,0 +1,38 @@ +// +// Copyright 2017 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 "hci_packetizer.h" + +namespace android { +namespace hardware { +namespace bluetooth { +namespace V1_0 { +namespace hikey { + +class HciPacketizerHikey : public hci::HciPacketizer { + public: + HciPacketizerHikey(hci::HciPacketReadyCallback packet_cb) + : HciPacketizer(packet_cb){}; + void OnDataReadyHikey(int fd); +}; + +} // namespace hikey +} // namespace V1_0 +} // namespace bluetooth +} // namespace hardware +} // namespace android diff --git a/bluetooth/service.cc b/bluetooth/service.cc new file mode 100644 index 00000000..5c591543 --- /dev/null +++ b/bluetooth/service.cc @@ -0,0 +1,36 @@ +// +// Copyright 2017 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-service.hikey" + +#include <android/hardware/bluetooth/1.0/IBluetoothHci.h> +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> + +#include "bluetooth_hci.h" + +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::bluetooth::V1_0::IBluetoothHci; +using ::android::hardware::bluetooth::V1_0::hikey::BluetoothHci; +using ::android::hardware::joinRpcThreadpool; +using ::android::sp; + +int main(int /* argc */, char** /* argv */) { + sp<IBluetoothHci> bluetooth = new BluetoothHci; + configureRpcThreadpool(1, true); + bluetooth->registerAsService(); + joinRpcThreadpool(); +} |