| // |
| // 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.1-btlinux" |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <poll.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <sys/socket.h> |
| |
| #include <utils/Log.h> |
| |
| #include "bluetooth_hci.h" |
| |
| #define BTPROTO_HCI 1 |
| |
| #define HCI_CHANNEL_USER 1 |
| #define HCI_CHANNEL_CONTROL 3 |
| #define HCI_DEV_NONE 0xffff |
| |
| /* reference from <kernel>/include/net/bluetooth/mgmt.h */ |
| #define MGMT_OP_INDEX_LIST 0x0003 |
| #define MGMT_EV_INDEX_ADDED 0x0004 |
| #define MGMT_EV_COMMAND_COMP 0x0001 |
| #define MGMT_EV_SIZE_MAX 1024 |
| #define WRITE_NO_INTR(fn) \ |
| do { \ |
| } while ((fn) == -1 && errno == EINTR) |
| |
| struct sockaddr_hci { |
| sa_family_t hci_family; |
| unsigned short hci_dev; |
| unsigned short hci_channel; |
| }; |
| |
| struct mgmt_pkt { |
| uint16_t opcode; |
| uint16_t index; |
| uint16_t len; |
| uint8_t data[MGMT_EV_SIZE_MAX]; |
| } __attribute__((packed)); |
| |
| struct mgmt_event_read_index { |
| uint16_t cc_opcode; |
| uint8_t status; |
| uint16_t num_intf; |
| uint16_t index[0]; |
| } __attribute__((packed)); |
| |
| namespace android { |
| namespace hardware { |
| namespace bluetooth { |
| namespace V1_1 { |
| namespace btlinux { |
| |
| int BluetoothHci::openBtHci() { |
| |
| ALOGI( "%s", __func__); |
| |
| int hci_interface = 0; |
| rfkill_state_ = NULL; |
| rfKill(1); |
| |
| int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); |
| if (fd < 0) { |
| ALOGE( "Bluetooth socket error: %s", strerror(errno)); |
| return -1; |
| } |
| bt_soc_fd_ = fd; |
| |
| if (waitHciDev(hci_interface)) { |
| ALOGE( "HCI interface (%d) not found", hci_interface); |
| ::close(fd); |
| return -1; |
| } |
| struct sockaddr_hci addr; |
| memset(&addr, 0, sizeof(addr)); |
| addr.hci_family = AF_BLUETOOTH; |
| addr.hci_dev = hci_interface; |
| addr.hci_channel = HCI_CHANNEL_USER; |
| if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { |
| ALOGE( "HCI Channel Control: %s", strerror(errno)); |
| ::close(fd); |
| return -1; |
| } |
| ALOGI( "HCI device ready"); |
| return fd; |
| } |
| |
| void BluetoothHci::closeBtHci() { |
| if (bt_soc_fd_ != -1) { |
| ::close(bt_soc_fd_); |
| bt_soc_fd_ = -1; |
| } |
| rfKill(0); |
| free(rfkill_state_); |
| } |
| |
| int BluetoothHci::waitHciDev(int hci_interface) { |
| struct sockaddr_hci addr; |
| struct pollfd fds[1]; |
| struct mgmt_pkt ev; |
| int fd; |
| int ret = 0; |
| |
| ALOGI( "%s", __func__); |
| fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); |
| if (fd < 0) { |
| ALOGE( "Bluetooth socket error: %s", strerror(errno)); |
| return -1; |
| } |
| memset(&addr, 0, sizeof(addr)); |
| addr.hci_family = AF_BLUETOOTH; |
| addr.hci_dev = HCI_DEV_NONE; |
| addr.hci_channel = HCI_CHANNEL_CONTROL; |
| if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { |
| ALOGE( "HCI Channel Control: %s", strerror(errno)); |
| ret = -1; |
| goto end; |
| } |
| |
| fds[0].fd = fd; |
| fds[0].events = POLLIN; |
| |
| /* Read Controller Index List Command */ |
| ev.opcode = MGMT_OP_INDEX_LIST; |
| ev.index = HCI_DEV_NONE; |
| ev.len = 0; |
| |
| ssize_t wrote; |
| WRITE_NO_INTR(wrote = write(fd, &ev, 6)); |
| if (wrote != 6) { |
| ALOGE( "Unable to write mgmt command: %s", strerror(errno)); |
| ret = -1; |
| goto end; |
| } |
| /* validate mentioned hci interface is present and registered with sock system */ |
| while (1) { |
| int n; |
| WRITE_NO_INTR(n = poll(fds, 1, -1)); |
| if (n == -1) { |
| ALOGE( "Poll error: %s", strerror(errno)); |
| ret = -1; |
| break; |
| } else if (n == 0) { |
| ALOGE( "Timeout, no HCI device detected"); |
| ret = -1; |
| break; |
| } |
| |
| if (fds[0].revents & POLLIN) { |
| WRITE_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt))); |
| if (n < 0) { |
| ALOGE( "Error reading control channel: %s", |
| strerror(errno)); |
| ret = -1; |
| break; |
| } |
| |
| if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) { |
| goto end; |
| } else if (ev.opcode == MGMT_EV_COMMAND_COMP) { |
| struct mgmt_event_read_index* cc; |
| int i; |
| |
| cc = (struct mgmt_event_read_index*)ev.data; |
| |
| if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue; |
| |
| for (i = 0; i < cc->num_intf; i++) { |
| if (cc->index[i] == hci_interface) goto end; |
| } |
| } |
| } |
| } |
| |
| end: |
| ::close(fd); |
| return ret; |
| } |
| |
| int BluetoothHci::findRfKill() { |
| char rfkill_type[64]; |
| char type[16]; |
| int fd, size, i; |
| for(i = 0; rfkill_state_ == NULL; i++) |
| { |
| snprintf(rfkill_type, sizeof(rfkill_type), "/sys/class/rfkill/rfkill%d/type", i); |
| if ((fd = open(rfkill_type, O_RDONLY)) < 0) |
| { |
| ALOGE("open(%s) failed: %s (%d)\n", rfkill_type, strerror(errno), errno); |
| return -1; |
| } |
| |
| size = read(fd, &type, sizeof(type)); |
| ::close(fd); |
| |
| if ((size >= 9) && !memcmp(type, "bluetooth", 9)) |
| { |
| ::asprintf(&rfkill_state_, "/sys/class/rfkill/rfkill%d/state", i); |
| break; |
| } |
| } |
| return 0; |
| } |
| |
| int BluetoothHci::rfKill(int block) { |
| int fd; |
| char on = (block)?'1':'0'; |
| if (findRfKill() != 0) return 0; |
| |
| fd = open(rfkill_state_, O_WRONLY); |
| if (fd < 0) { |
| ALOGE( "Unable to open /dev/rfkill"); |
| return -1; |
| } |
| ssize_t len; |
| WRITE_NO_INTR(len = write(fd, &on, 1)); |
| if (len < 0) { |
| ALOGE( "Failed to change rfkill state"); |
| ::close(fd); |
| return -1; |
| } |
| ::close(fd); |
| return 0; |
| } |
| |
| class BluetoothDeathRecipient : public hidl_death_recipient { |
| public: |
| BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {} |
| |
| void serviceDied( |
| uint64_t /*cookie*/, |
| const wp<::android::hidl::base::V1_0::IBase>& /*who*/) override { |
| ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died"); |
| has_died_ = true; |
| mHci->close(); |
| } |
| sp<IBluetoothHci> 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<void> BluetoothHci::initialize( |
| const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) { |
| return initialize_impl(cb, nullptr); |
| } |
| |
| Return<void> BluetoothHci::initialize_1_1( |
| const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) { |
| return initialize_impl(cb, cb); |
| } |
| |
| Return<void> BluetoothHci::initialize_impl( |
| const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb, |
| const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) { |
| 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); |
| int hci_fd = openBtHci(); |
| auto hidl_status = cb->initializationComplete( |
| hci_fd > 0 ? V1_0::Status::SUCCESS : V1_0::Status::INITIALIZATION_ERROR); |
| if (!hidl_status.isOk()) { |
| ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)"); |
| } |
| hci::H4Protocol* h4_hci = new hci::H4Protocol( |
| hci_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); }, |
| [cb_1_1](const hidl_vec<uint8_t>& packet) { |
| cb_1_1->isoDataReceived(packet); |
| }); |
| |
| fd_watcher_.WatchFdForNonBlockingReads( |
| hci_fd, [h4_hci](int fd) { h4_hci->OnDataReady(fd); }); |
| hci_handle_ = h4_hci; |
| |
| unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) { |
| if (death_recipient->getHasDied()) |
| ALOGI("Skipping unlink call, service died."); |
| else |
| cb->unlinkToDeath(death_recipient); |
| }; |
| |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::close() { |
| ALOGI("BluetoothHci::close()"); |
| unlink_cb_(death_recipient_); |
| fd_watcher_.StopWatchingFileDescriptors(); |
| |
| if (hci_handle_ != nullptr) { |
| delete hci_handle_; |
| hci_handle_ = nullptr; |
| } |
| closeBtHci(); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& command) { |
| sendDataToController(HCI_DATA_TYPE_COMMAND, command); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& data) { |
| sendDataToController(HCI_DATA_TYPE_ACL, data); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& data) { |
| sendDataToController(HCI_DATA_TYPE_SCO, data); |
| return Void(); |
| } |
| |
| Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& data) { |
| sendDataToController(HCI_DATA_TYPE_ISO, data); |
| return Void(); |
| } |
| |
| void BluetoothHci::sendDataToController(const uint8_t type, |
| const hidl_vec<uint8_t>& data) { |
| hci_handle_->Send(type, data.data(), data.size()); |
| } |
| |
| IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) { |
| return new BluetoothHci(); |
| } |
| |
| } // namespace btlinux |
| } // namespace V1_1 |
| } // namespace bluetooth |
| } // namespace hardware |
| } // namespace android |