summaryrefslogtreecommitdiff
path: root/tools/btinfo.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2014-01-01 22:14:48 -0800
committerMarcel Holtmann <marcel@holtmann.org>2014-01-01 22:14:48 -0800
commitfbb5ab3f4719ab6e561bcb2d86e680d9e72d2d11 (patch)
tree6accf16b0493f650eb1dd175d899552c6c428bdc /tools/btinfo.c
parent3a2df24e5d327bce34e30dc3a5091c83c5fea562 (diff)
downloadbluez-fbb5ab3f4719ab6e561bcb2d86e680d9e72d2d11.tar.gz
tools: Automatically powern on/off controller if needed
Diffstat (limited to 'tools/btinfo.c')
-rw-r--r--tools/btinfo.c125
1 files changed, 113 insertions, 12 deletions
diff --git a/tools/btinfo.c b/tools/btinfo.c
index 773d1d0c8..bcb564eb8 100644
--- a/tools/btinfo.c
+++ b/tools/btinfo.c
@@ -28,9 +28,12 @@
#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"
@@ -42,8 +45,53 @@
#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)
{
@@ -65,7 +113,7 @@ static void shutdown_device(void)
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,
@@ -82,8 +130,16 @@ static void local_version_callback(const void *data, uint8_t size,
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);
}
@@ -103,7 +159,7 @@ static void local_features_callback(const void *data, uint8_t size,
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);
@@ -159,7 +215,8 @@ static void usage(void)
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' },
{ }
@@ -168,16 +225,17 @@ static const struct option main_options[] = {
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;
@@ -194,6 +252,9 @@ int main(int argc, char *argv[])
index = atoi(str);
break;
case 'r':
+ reset_on_init = true;
+ break;
+ case 'R':
use_raw = true;
break;
case 'v':
@@ -234,14 +295,43 @@ int main(int argc, char *argv[])
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) {
@@ -249,7 +339,8 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- reset_required = true;
+ reset_on_init = true;
+ reset_on_shutdown = true;
}
if (!func(argc - optind - 1, argv + optind + 1)) {
@@ -261,5 +352,15 @@ int main(int argc, char *argv[])
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;
}