Diff between 3a2df24e5d327bce34e30dc3a5091c83c5fea562 and fbb5ab3f4719ab6e561bcb2d86e680d9e72d2d11

Changed Files

File Additions Deletions Status
tools/btinfo.c +113 -12 modified

Full Patch

diff --git a/tools/btinfo.c b/tools/btinfo.c
index 773d1d0..bcb564e 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;
 }