3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011-2012 Intel Corporation
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
38 #include "monitor/mainloop.h"
39 #include "monitor/bt.h"
40 #include "src/shared/util.h"
41 #include "src/shared/hci.h"
45 struct hci_dev_stats {
72 struct hci_dev_stats stat;
75 #define HCIDEVUP _IOW('H', 201, int)
76 #define HCIDEVDOWN _IOW('H', 202, int)
77 #define HCIGETDEVINFO _IOR('H', 211, int)
79 #define HCI_UP (1 << 0)
81 #define HCI_BREDR 0x00
84 static struct hci_dev_info hci_info;
85 static uint8_t hci_type;
86 static struct bt_hci *hci_dev;
88 static bool reset_on_init = false;
89 static bool reset_on_shutdown = false;
91 static void shutdown_timeout(int id, void *user_data)
93 mainloop_remove_timeout(id);
98 static void shutdown_complete(const void *data, uint8_t size, void *user_data)
100 unsigned int id = PTR_TO_UINT(user_data);
102 shutdown_timeout(id, NULL);
105 static void shutdown_device(void)
109 bt_hci_flush(hci_dev);
111 if (reset_on_shutdown) {
112 id = mainloop_add_timeout(5000, shutdown_timeout, NULL, NULL);
114 bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
115 shutdown_complete, UINT_TO_PTR(id), NULL);
120 static void local_version_callback(const void *data, uint8_t size,
123 const struct bt_hci_rsp_read_local_version *rsp = data;
125 printf("HCI version: %u\n", rsp->hci_ver);
126 printf("HCI revision: %u\n", le16_to_cpu(rsp->hci_rev));
130 printf("LMP version: %u\n", rsp->lmp_ver);
131 printf("LMP subversion: %u\n", le16_to_cpu(rsp->lmp_subver));
134 printf("PAL version: %u\n", rsp->lmp_ver);
135 printf("PAL subversion: %u\n", le16_to_cpu(rsp->lmp_subver));
139 printf("Manufacturer: %u\n", le16_to_cpu(rsp->manufacturer));
142 static void local_commands_callback(const void *data, uint8_t size,
148 static void local_features_callback(const void *data, uint8_t size,
151 bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0,
152 local_commands_callback, NULL, NULL);
155 static bool cmd_local(int argc, char *argv[])
158 bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
161 bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
162 local_version_callback, NULL, NULL);
164 bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
165 local_features_callback, NULL, NULL);
170 typedef bool (*cmd_func_t)(int argc, char *argv[]);
172 static const struct {
177 { "local", cmd_local, "Print local controller details" },
181 static void signal_callback(int signum, void *user_data)
183 static bool terminated = false;
196 static void usage(void)
200 printf("btinfo - Bluetooth device testing tool\n"
202 printf("\tbtinfo [options] <command>\n");
204 "\t-i, --index <num> Use specified controller\n"
205 "\t-h, --help Show help options\n");
206 printf("commands:\n");
207 for (i = 0; cmd_table[i].name; i++)
208 printf("\t%-25s%s\n", cmd_table[i].name, cmd_table[i].help);
211 static const struct option main_options[] = {
212 { "index", required_argument, NULL, 'i' },
213 { "reset", no_argument, NULL, 'r' },
214 { "raw", no_argument, NULL, 'R' },
215 { "version", no_argument, NULL, 'v' },
216 { "help", no_argument, NULL, 'h' },
220 int main(int argc, char *argv[])
222 cmd_func_t func = NULL;
225 bool use_raw = false;
226 bool power_down = false;
228 int fd, i, exit_status;
233 opt = getopt_long(argc, argv, "i:rRvh", main_options, NULL);
239 if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
243 if (!isdigit(*str)) {
250 reset_on_init = true;
256 printf("%s\n", VERSION);
266 if (argc - optind < 1) {
267 fprintf(stderr, "Missing command argument\n");
271 for (i = 0; cmd_table[i].name; i++) {
272 if (!strcmp(cmd_table[i].name, argv[optind])) {
273 func = cmd_table[i].func;
279 fprintf(stderr, "Unsupported command specified\n");
286 sigaddset(&mask, SIGINT);
287 sigaddset(&mask, SIGTERM);
289 mainloop_set_signal(&mask, signal_callback, NULL, NULL);
291 printf("Bluetooth information utility ver %s\n", VERSION);
293 fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
295 perror("Failed to open HCI raw socket");
299 memset(&hci_info, 0, sizeof(hci_info));
300 hci_info.dev_id = index;
302 if (ioctl(fd, HCIGETDEVINFO, (void *) &hci_info) < 0) {
303 perror("Failed to get HCI device information");
308 if (use_raw && !(hci_info.flags & HCI_UP)) {
309 printf("Powering on controller\n");
311 if (ioctl(fd, HCIDEVUP, hci_info.dev_id) < 0) {
312 perror("Failed to power on controller");
322 hci_type = (hci_info.type & 0x30) >> 4;
325 hci_dev = bt_hci_new_raw_device(index);
327 fprintf(stderr, "Failed to open HCI raw device\n");
331 hci_dev = bt_hci_new_user_channel(index);
333 fprintf(stderr, "Failed to open HCI user channel\n");
337 reset_on_init = true;
338 reset_on_shutdown = true;
341 if (!func(argc - optind - 1, argv + optind + 1)) {
342 bt_hci_unref(hci_dev);
346 exit_status = mainloop_run();
348 bt_hci_unref(hci_dev);
350 if (use_raw && power_down) {
351 fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
353 printf("Powering down controller\n");
355 if (ioctl(fd, HCIDEVDOWN, hci_info.dev_id) < 0)
356 perror("Failed to power down controller");