diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-01-01 22:14:48 -0800 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-01-01 22:14:48 -0800 |
commit | fbb5ab3f4719ab6e561bcb2d86e680d9e72d2d11 (patch) | |
tree | 6accf16b0493f650eb1dd175d899552c6c428bdc /tools/btinfo.c | |
parent | 3a2df24e5d327bce34e30dc3a5091c83c5fea562 (diff) | |
download | bluez-fbb5ab3f4719ab6e561bcb2d86e680d9e72d2d11.tar.gz |
tools: Automatically powern on/off controller if needed
Diffstat (limited to 'tools/btinfo.c')
-rw-r--r-- | tools/btinfo.c | 125 |
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; } |