| // |
| // 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 <android-base/logging.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <unistd.h> |
| #include <utils/Log.h> |
| |
| namespace android { |
| namespace hardware { |
| namespace bluetooth { |
| namespace V1_0 { |
| namespace hikey { |
| |
| using android::hardware::hidl_vec; |
| |
| Return<void> BluetoothHci::initialize( |
| const ::android::sp<IBluetoothHciCallbacks>& cb) { |
| ALOGI("BluetoothHci::initialize()"); |
| |
| hci_tty_fd_ = open("/dev/hci_tty", O_RDWR); |
| if (hci_tty_fd_ < 0) { |
| ALOGE("%s: Can't open hci_tty (%s)", __func__, strerror(errno)); |
| cb->initializationComplete(Status::INITIALIZATION_ERROR); |
| return Void(); |
| } |
| |
| event_cb_ = cb; |
| |
| hci_ = new hci::H4Protocol( |
| hci_tty_fd_, |
| [cb](const hidl_vec<uint8_t>& packet) { cb->hciEventReceived(packet); }, |
| [cb](const hidl_vec<uint8_t>& packet) { cb->aclDataReceived(packet); }, |
| [cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); }); |
| |
| // Use a socket pair to enforce the TI FIONREAD requirement. |
| int sockfd[2]; |
| socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd); |
| int shim_fd = sockfd[0]; |
| int for_hci = sockfd[1]; |
| |
| fd_watcher_.WatchFdForNonBlockingReads(hci_tty_fd_, [this, shim_fd](int fd) { |
| int tty_bytes = 0; |
| if (TEMP_FAILURE_RETRY(ioctl(fd, FIONREAD, &tty_bytes))) |
| 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 bytes_written = |
| TEMP_FAILURE_RETRY(write(shim_fd, tmp_buffer, tty_bytes)); |
| CHECK(static_cast<int>(bytes_written) == tty_bytes); |
| delete[] tmp_buffer; |
| }); |
| |
| fd_watcher_.WatchFdForNonBlockingReads( |
| for_hci, [this](int fd) { hci_->OnDataReady(fd); }); |
| |
| cb->initializationComplete(Status::SUCCESS); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::close() { |
| ALOGI("BluetoothHci::close()"); |
| |
| if (hci_tty_fd_ >= 0) { |
| fd_watcher_.StopWatchingFileDescriptors(); |
| ::close(hci_tty_fd_); |
| hci_tty_fd_ = -1; |
| } |
| |
| if (hci_ != nullptr) { |
| delete hci_; |
| hci_ = nullptr; |
| } |
| |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& packet) { |
| hci_->Send(HCI_PACKET_TYPE_COMMAND, packet.data(), packet.size()); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& packet) { |
| hci_->Send(HCI_PACKET_TYPE_ACL_DATA, packet.data(), packet.size()); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& packet) { |
| hci_->Send(HCI_PACKET_TYPE_SCO_DATA, packet.data(), packet.size()); |
| return Void(); |
| } |
| |
| } // namespace hikey |
| } // namespace V1_0 |
| } // namespace bluetooth |
| } // namespace hardware |
| } // namespace android |