mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 21:37:44 +00:00
[Description] when driver re-register hci device, it may register hci 1 [Root Cause] In the kernel mechanism, there may be a timing issue. when driver re-register hci device,kernel may not completely unregister hci 0.But aidl only open hci 0. [Solution] assign a value to the hci interface based on the device node found by AIDL [Test Report] Insert the bt chip into the usb 2.0 port, and then suspend the TV. The bt chip will be disconnected due to the USB power outage. And then quickly resume the TV,check whether the Bluetooth state is on. Suspend and resume for several times, check for bt state. Change-Id: I57fd4a22c956e0cf2b4a516247c258493163e51a BUG: 314149416
298 lines
7.3 KiB
C++
298 lines
7.3 KiB
C++
/*
|
|
* Copyright 2022 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.service.default"
|
|
|
|
#include "net_bluetooth_mgmt.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <log/log.h>
|
|
#include <poll.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
|
|
#include <cerrno>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
// Definitions imported from <linux/net/bluetooth/bluetooth.h>
|
|
#define BTPROTO_HCI 1
|
|
|
|
// Definitions imported from <linux/net/bluetooth/hci_sock.h>
|
|
#define HCI_CHANNEL_USER 1
|
|
#define HCI_CHANNEL_CONTROL 3
|
|
#define HCI_DEV_NONE 0xffff
|
|
|
|
struct sockaddr_hci {
|
|
sa_family_t hci_family;
|
|
unsigned short hci_dev;
|
|
unsigned short hci_channel;
|
|
};
|
|
|
|
// Definitions imported from <linux/net/bluetooth/mgmt.h>
|
|
#define MGMT_OP_READ_INDEX_LIST 0x0003
|
|
#define MGMT_EV_INDEX_ADDED 0x0004
|
|
#define MGMT_EV_CMD_COMPLETE 0x0001
|
|
#define MGMT_PKT_SIZE_MAX 1024
|
|
#define MGMT_INDEX_NONE 0xFFFF
|
|
|
|
struct mgmt_pkt {
|
|
uint16_t opcode;
|
|
uint16_t index;
|
|
uint16_t len;
|
|
uint8_t data[MGMT_PKT_SIZE_MAX];
|
|
} __attribute__((packed));
|
|
|
|
struct mgmt_ev_read_index_list {
|
|
uint16_t opcode;
|
|
uint8_t status;
|
|
uint16_t num_controllers;
|
|
uint16_t index[];
|
|
} __attribute__((packed));
|
|
|
|
// Definitions imported from <linux/rfkill.h>
|
|
#define RFKILL_STATE_SOFT_BLOCKED 0
|
|
#define RFKILL_STATE_UNBLOCKED 1
|
|
#define RFKILL_STATE_HARD_BLOCKED 2
|
|
|
|
#define RFKILL_TYPE_BLUETOOTH 2
|
|
|
|
#define RFKILL_OP_ADD 0
|
|
#define RFKILL_OP_CHANGE 2
|
|
|
|
struct rfkill_event {
|
|
uint32_t idx;
|
|
uint8_t type;
|
|
uint8_t op;
|
|
uint8_t soft;
|
|
uint8_t hard;
|
|
} __attribute__((packed));
|
|
|
|
namespace aidl::android::hardware::bluetooth::impl {
|
|
|
|
// Wait indefinitely for the selected HCI interface to be enabled in the
|
|
// bluetooth driver.
|
|
int NetBluetoothMgmt::waitHciDev(int hci_interface) {
|
|
ALOGI("waiting for hci interface %d", hci_interface);
|
|
|
|
int ret = -1;
|
|
struct mgmt_pkt cmd;
|
|
struct pollfd pollfd;
|
|
struct sockaddr_hci hci_addr = {
|
|
.hci_family = AF_BLUETOOTH,
|
|
.hci_dev = HCI_DEV_NONE,
|
|
.hci_channel = HCI_CHANNEL_CONTROL,
|
|
};
|
|
|
|
// Open and bind a socket to the bluetooth control interface in the
|
|
// kernel driver, used to send control commands and receive control
|
|
// events.
|
|
int fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
|
if (fd < 0) {
|
|
ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
|
|
ALOGE("unable to bind bluetooth control channel: %s", strerror(errno));
|
|
goto end;
|
|
}
|
|
|
|
// Send the control command [Read Index List].
|
|
cmd = {
|
|
.opcode = MGMT_OP_READ_INDEX_LIST,
|
|
.index = MGMT_INDEX_NONE,
|
|
.len = 0,
|
|
};
|
|
|
|
if (write(fd, &cmd, 6) != 6) {
|
|
ALOGE("error writing mgmt command: %s", strerror(errno));
|
|
goto end;
|
|
}
|
|
|
|
// Poll the control socket waiting for the command response,
|
|
// and subsequent [Index Added] events. The loops continue without
|
|
// timeout until the selected hci interface is detected.
|
|
pollfd = {.fd = fd, .events = POLLIN};
|
|
|
|
for (;;) {
|
|
ret = poll(&pollfd, 1, -1);
|
|
|
|
// Poll interrupted, try again.
|
|
if (ret == -1 && (errno == EINTR || errno == EAGAIN)) {
|
|
continue;
|
|
}
|
|
|
|
// Poll failure, abandon.
|
|
if (ret == -1) {
|
|
ALOGE("poll error: %s", strerror(errno));
|
|
break;
|
|
}
|
|
|
|
// Spurious wakeup, try again.
|
|
if (ret == 0 || (pollfd.revents & POLLIN) == 0) {
|
|
continue;
|
|
}
|
|
|
|
// Read the next control event.
|
|
struct mgmt_pkt ev {};
|
|
ret = read(fd, &ev, sizeof(ev));
|
|
if (ret < 0) {
|
|
ALOGE("error reading mgmt event: %s", strerror(errno));
|
|
goto end;
|
|
}
|
|
|
|
// Received [Read Index List] command response.
|
|
if (ev.opcode == MGMT_EV_CMD_COMPLETE) {
|
|
struct mgmt_ev_read_index_list* data =
|
|
(struct mgmt_ev_read_index_list*)ev.data;
|
|
|
|
for (int i = 0; i < data->num_controllers; i++) {
|
|
if (data->index[i] >= hci_interface) {
|
|
ALOGI("hci interface %d found", data->index[i]);
|
|
ret = data->index[i];
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Received [Index Added] event.
|
|
if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
|
|
ALOGI("hci interface %d added", hci_interface);
|
|
ret = 0;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
end:
|
|
::close(fd);
|
|
return ret;
|
|
}
|
|
|
|
int NetBluetoothMgmt::openRfkill() {
|
|
int fd = open("/dev/rfkill", O_RDWR);
|
|
if (fd < 0) {
|
|
ALOGE("unable to open /dev/rfkill: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
|
ALOGE("unable to set rfkill control device to non-blocking: %s",
|
|
strerror(errno));
|
|
::close(fd);
|
|
return -1;
|
|
}
|
|
|
|
for (;;) {
|
|
struct rfkill_event event {};
|
|
ssize_t res = read(fd, &event, sizeof(event));
|
|
if (res < 0) {
|
|
ALOGE("error reading rfkill events: %s", strerror(errno));
|
|
break;
|
|
}
|
|
|
|
ALOGI("index:%d type:%d op:%d", event.idx, event.type, event.op);
|
|
|
|
if (event.op == RFKILL_OP_ADD && event.type == RFKILL_TYPE_BLUETOOTH) {
|
|
rfkill_bt_index_ = event.idx;
|
|
rfkill_fd_ = fd;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
::close(fd);
|
|
return -1;
|
|
}
|
|
|
|
// Block or unblock Bluetooth.
|
|
int NetBluetoothMgmt::rfkill(int block) {
|
|
if (rfkill_fd_ == -1) {
|
|
openRfkill();
|
|
}
|
|
|
|
if (rfkill_fd_ == -1) {
|
|
ALOGE("rfkill unavailable");
|
|
return -1;
|
|
}
|
|
|
|
struct rfkill_event event = {
|
|
.idx = static_cast<uint32_t>(rfkill_bt_index_),
|
|
.type = RFKILL_TYPE_BLUETOOTH,
|
|
.op = RFKILL_OP_CHANGE,
|
|
.soft = static_cast<uint8_t>(block),
|
|
.hard = 0,
|
|
};
|
|
|
|
int res = write(rfkill_fd_, &event, sizeof(event));
|
|
if (res < 0) {
|
|
ALOGE("error writing rfkill command: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int NetBluetoothMgmt::openHci(int hci_interface) {
|
|
ALOGI("opening hci interface %d", hci_interface);
|
|
|
|
// Block Bluetooth.
|
|
rfkill(1);
|
|
|
|
// Wait for the HCI interface to complete initialization or to come online.
|
|
hci_interface = waitHciDev(hci_interface);
|
|
if (hci_interface < 0) {
|
|
ALOGE("hci interface not found");
|
|
return -1;
|
|
}
|
|
|
|
// Open the raw HCI socket.
|
|
int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
|
if (fd < 0) {
|
|
ALOGE("unable to open raw bluetooth socket: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
struct sockaddr_hci hci_addr = {
|
|
.hci_family = AF_BLUETOOTH,
|
|
.hci_dev = static_cast<uint16_t>(hci_interface),
|
|
.hci_channel = HCI_CHANNEL_USER,
|
|
};
|
|
|
|
// Bind the socket to the selected interface.
|
|
if (bind(fd, (struct sockaddr*)&hci_addr, sizeof(hci_addr)) < 0) {
|
|
ALOGE("unable to bind bluetooth user channel: %s", strerror(errno));
|
|
::close(fd);
|
|
return -1;
|
|
}
|
|
|
|
ALOGI("hci interface %d ready", hci_interface);
|
|
bt_fd_ = fd;
|
|
return fd;
|
|
}
|
|
|
|
void NetBluetoothMgmt::closeHci() {
|
|
if (bt_fd_ != -1) {
|
|
::close(bt_fd_);
|
|
bt_fd_ = -1;
|
|
}
|
|
|
|
// Unblock Bluetooth.
|
|
rfkill(0);
|
|
}
|
|
|
|
} // namespace aidl::android::hardware::bluetooth::impl
|