diff --git a/tools/btinfo.c b/tools/btinfo.c
index 773d1d0..bcb564e 100644
--- a/tools/btinfo.c
+++ b/tools/btinfo.c
#include <ctype.h>
#include <stdio.h>
+#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
#include "monitor/mainloop.h"
#include "monitor/bt.h"
#define cpu_to_le16(val) (val)
#define cpu_to_le32(val) (val)
+#define BTPROTO_HCI 1
+
+struct hci_dev_stats {
+ uint32_t err_rx;
+ uint32_t err_tx;
+ uint32_t cmd_tx;
+ uint32_t evt_rx;
+ uint32_t acl_tx;
+ uint32_t acl_rx;
+ uint32_t sco_tx;
+ uint32_t sco_rx;
+ uint32_t byte_rx;
+ uint32_t byte_tx;
+};
+
+struct hci_dev_info {
+ uint16_t dev_id;
+ char name[8];
+ uint8_t bdaddr[6];
+ uint32_t flags;
+ uint8_t type;
+ uint8_t features[8];
+ uint32_t pkt_type;
+ uint32_t link_policy;
+ uint32_t link_mode;
+ uint16_t acl_mtu;
+ uint16_t acl_pkts;
+ uint16_t sco_mtu;
+ uint16_t sco_pkts;
+ struct hci_dev_stats stat;
+};
+
+#define HCIDEVUP _IOW('H', 201, int)
+#define HCIDEVDOWN _IOW('H', 202, int)
+#define HCIGETDEVINFO _IOR('H', 211, int)
+
+#define HCI_UP (1 << 0)
+
+#define HCI_BREDR 0x00
+#define HCI_AMP 0x01
+
+static struct hci_dev_info hci_info;
+static uint8_t hci_type;
static struct bt_hci *hci_dev;
-static bool reset_required = false;
+
+static bool reset_on_init = false;
+static bool reset_on_shutdown = false;
static void shutdown_timeout(int id, void *user_data)
{
bt_hci_flush(hci_dev);
- if (reset_required) {
+ if (reset_on_shutdown) {
id = mainloop_add_timeout(5, shutdown_timeout, NULL, NULL);
bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
printf("HCI version: %u\n", rsp->hci_ver);
printf("HCI revision: %u\n", rsp->hci_rev);
- printf("LMP version: %u\n", rsp->lmp_ver);
- printf("LMP subversion: %u\n", rsp->lmp_subver);
+ switch (hci_type) {
+ case HCI_BREDR:
+ printf("LMP version: %u\n", rsp->lmp_ver);
+ printf("LMP subversion: %u\n", rsp->lmp_subver);
+ break;
+ case HCI_AMP:
+ printf("PAL version: %u\n", rsp->lmp_ver);
+ printf("PAL subversion: %u\n", rsp->lmp_subver);
+ break;
+ }
printf("Manufacturer: %u\n", rsp->manufacturer);
}
static bool cmd_local(int argc, char *argv[])
{
- if (reset_required)
+ if (reset_on_init)
bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
NULL, NULL, NULL);
static const struct option main_options[] = {
{ "index", required_argument, NULL, 'i' },
- { "raw", no_argument, NULL, 'r' },
+ { "reset", no_argument, NULL, 'r' },
+ { "raw", no_argument, NULL, 'R' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
int main(int argc, char *argv[])
{
cmd_func_t func = NULL;
- bool use_raw = false;
uint16_t index = 0;
const char *str;
+ bool use_raw = false;
+ bool power_down = false;
sigset_t mask;
- int i, exit_status;
+ int fd, i, exit_status;
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "i:rvh", main_options, NULL);
+ opt = getopt_long(argc, argv, "i:rRvh", main_options, NULL);
if (opt < 0)
break;
index = atoi(str);
break;
case 'r':
+ reset_on_init = true;
+ break;
+ case 'R':
use_raw = true;
break;
case 'v':
printf("Bluetooth information utility ver %s\n", VERSION);
+ fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
+ if (fd < 0) {
+ perror("Failed to open HCI raw socket");
+ return EXIT_FAILURE;
+ }
+
+ memset(&hci_info, 0, sizeof(hci_info));
+ hci_info.dev_id = index;
+
+ if (ioctl(fd, HCIGETDEVINFO, (void *) &hci_info) < 0) {
+ perror("Failed to get HCI device information");
+ close(fd);
+ return EXIT_FAILURE;
+ }
+
+ if (use_raw && !(hci_info.flags & HCI_UP)) {
+ printf("Powering on controller\n");
+
+ if (ioctl(fd, HCIDEVUP, hci_info.dev_id) < 0) {
+ perror("Failed to power on controller");
+ close(fd);
+ return EXIT_FAILURE;
+ }
+
+ power_down = true;
+ }
+
+ close(fd);
+
+ hci_type = (hci_info.type & 0x30) >> 4;
+
if (use_raw) {
hci_dev = bt_hci_new_raw_device(index);
if (!hci_dev) {
fprintf(stderr, "Failed to open HCI raw device\n");
return EXIT_FAILURE;
}
-
- reset_required = false;
} else {
hci_dev = bt_hci_new_user_channel(index);
if (!hci_dev) {
return EXIT_FAILURE;
}
- reset_required = true;
+ reset_on_init = true;
+ reset_on_shutdown = true;
}
if (!func(argc - optind - 1, argv + optind + 1)) {
bt_hci_unref(hci_dev);
+ if (use_raw && power_down) {
+ fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
+ if (fd >= 0) {
+ printf("Powering down controller\n");
+
+ if (ioctl(fd, HCIDEVDOWN, hci_info.dev_id) < 0)
+ perror("Failed to power down controller");
+ }
+ }
+
return exit_status;
}