tizen 2.3 release
[framework/connectivity/bluez.git] / tools / btinfo.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011-2012  Intel Corporation
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
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.
13  *
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.
18  *
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
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <getopt.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37
38 #include "monitor/mainloop.h"
39 #include "monitor/bt.h"
40 #include "src/shared/util.h"
41 #include "src/shared/hci.h"
42
43 #define BTPROTO_HCI     1
44
45 struct hci_dev_stats {
46         uint32_t err_rx;
47         uint32_t err_tx;
48         uint32_t cmd_tx;
49         uint32_t evt_rx;
50         uint32_t acl_tx;
51         uint32_t acl_rx;
52         uint32_t sco_tx;
53         uint32_t sco_rx;
54         uint32_t byte_rx;
55         uint32_t byte_tx;
56 };
57
58 struct hci_dev_info {
59         uint16_t dev_id;
60         char     name[8];
61         uint8_t  bdaddr[6];
62         uint32_t flags;
63         uint8_t  type;
64         uint8_t  features[8];
65         uint32_t pkt_type;
66         uint32_t link_policy;
67         uint32_t link_mode;
68         uint16_t acl_mtu;
69         uint16_t acl_pkts;
70         uint16_t sco_mtu;
71         uint16_t sco_pkts;
72         struct   hci_dev_stats stat;
73 };
74
75 #define HCIDEVUP        _IOW('H', 201, int)
76 #define HCIDEVDOWN      _IOW('H', 202, int)
77 #define HCIGETDEVINFO   _IOR('H', 211, int)
78
79 #define HCI_UP          (1 << 0)
80
81 #define HCI_BREDR       0x00
82 #define HCI_AMP         0x01
83
84 static struct hci_dev_info hci_info;
85 static uint8_t hci_type;
86 static struct bt_hci *hci_dev;
87
88 static bool reset_on_init = false;
89 static bool reset_on_shutdown = false;
90
91 static void shutdown_timeout(int id, void *user_data)
92 {
93         mainloop_remove_timeout(id);
94
95         mainloop_quit();
96 }
97
98 static void shutdown_complete(const void *data, uint8_t size, void *user_data)
99 {
100         unsigned int id = PTR_TO_UINT(user_data);
101
102         shutdown_timeout(id, NULL);
103 }
104
105 static void shutdown_device(void)
106 {
107         unsigned int id;
108
109         bt_hci_flush(hci_dev);
110
111         if (reset_on_shutdown) {
112                 id = mainloop_add_timeout(5000, shutdown_timeout, NULL, NULL);
113
114                 bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
115                                 shutdown_complete, UINT_TO_PTR(id), NULL);
116         } else
117                 mainloop_quit();
118 }
119
120 static void local_version_callback(const void *data, uint8_t size,
121                                                         void *user_data)
122 {
123         const struct bt_hci_rsp_read_local_version *rsp = data;
124
125         printf("HCI version: %u\n", rsp->hci_ver);
126         printf("HCI revision: %u\n", le16_to_cpu(rsp->hci_rev));
127
128         switch (hci_type) {
129         case HCI_BREDR:
130                 printf("LMP version: %u\n", rsp->lmp_ver);
131                 printf("LMP subversion: %u\n", le16_to_cpu(rsp->lmp_subver));
132                 break;
133         case HCI_AMP:
134                 printf("PAL version: %u\n", rsp->lmp_ver);
135                 printf("PAL subversion: %u\n", le16_to_cpu(rsp->lmp_subver));
136                 break;
137         }
138
139         printf("Manufacturer: %u\n", le16_to_cpu(rsp->manufacturer));
140 }
141
142 static void local_commands_callback(const void *data, uint8_t size,
143                                                         void *user_data)
144 {
145         shutdown_device();
146 }
147
148 static void local_features_callback(const void *data, uint8_t size,
149                                                         void *user_data)
150 {
151         bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0,
152                                         local_commands_callback, NULL, NULL);
153 }
154
155 static bool cmd_local(int argc, char *argv[])
156 {
157         if (reset_on_init)
158                 bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
159                                                 NULL, NULL, NULL);
160
161         bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
162                                         local_version_callback, NULL, NULL);
163
164         bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
165                                         local_features_callback, NULL, NULL);
166
167         return true;
168 }
169
170 typedef bool (*cmd_func_t)(int argc, char *argv[]);
171
172 static const struct {
173         const char *name;
174         cmd_func_t func;
175         const char *help;
176 } cmd_table[] = {
177         { "local", cmd_local, "Print local controller details" },
178         { }
179 };
180
181 static void signal_callback(int signum, void *user_data)
182 {
183         static bool terminated = false;
184
185         switch (signum) {
186         case SIGINT:
187         case SIGTERM:
188                 if (!terminated) {
189                         shutdown_device();
190                         terminated = true;
191                 }
192                 break;
193         }
194 }
195
196 static void usage(void)
197 {
198         int i;
199
200         printf("btinfo - Bluetooth device testing tool\n"
201                 "Usage:\n");
202         printf("\tbtinfo [options] <command>\n");
203         printf("options:\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);
209 }
210
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' },
217         { }
218 };
219
220 int main(int argc, char *argv[])
221 {
222         cmd_func_t func = NULL;
223         uint16_t index = 0;
224         const char *str;
225         bool use_raw = false;
226         bool power_down = false;
227         sigset_t mask;
228         int fd, i, exit_status;
229
230         for (;;) {
231                 int opt;
232
233                 opt = getopt_long(argc, argv, "i:rRvh", main_options, NULL);
234                 if (opt < 0)
235                         break;
236
237                 switch (opt) {
238                 case 'i':
239                         if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
240                                 str = optarg + 3;
241                         else
242                                 str = optarg;
243                         if (!isdigit(*str)) {
244                                 usage();
245                                 return EXIT_FAILURE;
246                         }
247                         index = atoi(str);
248                         break;
249                 case 'r':
250                         reset_on_init = true;
251                         break;
252                 case 'R':
253                         use_raw = true;
254                         break;
255                 case 'v':
256                         printf("%s\n", VERSION);
257                         return EXIT_SUCCESS;
258                 case 'h':
259                         usage();
260                         return EXIT_SUCCESS;
261                 default:
262                         return EXIT_FAILURE;
263                 }
264         }
265
266         if (argc - optind < 1) {
267                 fprintf(stderr, "Missing command argument\n");
268                 return EXIT_FAILURE;
269         }
270
271         for (i = 0; cmd_table[i].name; i++) {
272                 if (!strcmp(cmd_table[i].name, argv[optind])) {
273                         func = cmd_table[i].func;
274                         break;
275                 }
276         }
277
278         if (!func) {
279                 fprintf(stderr, "Unsupported command specified\n");
280                 return EXIT_FAILURE;
281         }
282
283         mainloop_init();
284
285         sigemptyset(&mask);
286         sigaddset(&mask, SIGINT);
287         sigaddset(&mask, SIGTERM);
288
289         mainloop_set_signal(&mask, signal_callback, NULL, NULL);
290
291         printf("Bluetooth information utility ver %s\n", VERSION);
292
293         fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
294         if (fd < 0) {
295                 perror("Failed to open HCI raw socket");
296                 return EXIT_FAILURE;
297         }
298
299         memset(&hci_info, 0, sizeof(hci_info));
300         hci_info.dev_id = index;
301
302         if (ioctl(fd, HCIGETDEVINFO, (void *) &hci_info) < 0) {
303                 perror("Failed to get HCI device information");
304                 close(fd);
305                 return EXIT_FAILURE;
306         }
307
308         if (use_raw && !(hci_info.flags & HCI_UP)) {
309                 printf("Powering on controller\n");
310
311                 if (ioctl(fd, HCIDEVUP, hci_info.dev_id) < 0) {
312                         perror("Failed to power on controller");
313                         close(fd);
314                         return EXIT_FAILURE;
315                 }
316
317                 power_down = true;
318         }
319
320         close(fd);
321
322         hci_type = (hci_info.type & 0x30) >> 4;
323
324         if (use_raw) {
325                 hci_dev = bt_hci_new_raw_device(index);
326                 if (!hci_dev) {
327                         fprintf(stderr, "Failed to open HCI raw device\n");
328                         return EXIT_FAILURE;
329                 }
330         } else {
331                 hci_dev = bt_hci_new_user_channel(index);
332                 if (!hci_dev) {
333                         fprintf(stderr, "Failed to open HCI user channel\n");
334                         return EXIT_FAILURE;
335                 }
336
337                 reset_on_init = true;
338                 reset_on_shutdown = true;
339         }
340
341         if (!func(argc - optind - 1, argv + optind + 1)) {
342                 bt_hci_unref(hci_dev);
343                 return EXIT_FAILURE;
344         }
345
346         exit_status = mainloop_run();
347
348         bt_hci_unref(hci_dev);
349
350         if (use_raw && power_down) {
351                 fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
352                 if (fd >= 0) {
353                         printf("Powering down controller\n");
354
355                         if (ioctl(fd, HCIDEVDOWN, hci_info.dev_id) < 0)
356                                 perror("Failed to power down controller");
357
358                         close(fd);
359                 }
360         }
361
362         return exit_status;
363 }