blob: 8507f7a10b118fbce7cdd04171153faa9e63dbe3 [file] [log] [blame]
//
// 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-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 MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
#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_0 {
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, MGMT_EV_POLL_TIMEOUT));
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) {}
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<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<IBluetoothHciCallbacks>& 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);
int hci_fd = openBtHci();
auto hidl_status = cb->initializationComplete(
hci_fd > 0 ? Status::SUCCESS : 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); });
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();
}
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_0
} // namespace bluetooth
} // namespace hardware
} // namespace android