Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / tools / btattach.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 <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <getopt.h>
36 #include <termios.h>
37 #include <sys/ioctl.h>
38 #include <poll.h>
39
40 #include "lib/bluetooth.h"
41 #include "lib/hci.h"
42 #include "lib/hci_lib.h"
43
44 #include "hciattach.h"
45 #include "monitor/bt.h"
46 #include "src/shared/mainloop.h"
47 #include "src/shared/timeout.h"
48 #include "src/shared/util.h"
49 #include "src/shared/hci.h"
50
51 static int open_serial(const char *path)
52 {
53         struct termios ti;
54         int fd, saved_ldisc, ldisc = N_HCI;
55
56         fd = open(path, O_RDWR | O_NOCTTY);
57         if (fd < 0) {
58                 perror("Failed to open serial port");
59                 return -1;
60         }
61
62         if (tcflush(fd, TCIOFLUSH) < 0) {
63                 perror("Failed to flush serial port");
64                 close(fd);
65                 return -1;
66         }
67
68         if (ioctl(fd, TIOCGETD, &saved_ldisc) < 0) {
69                 perror("Failed get serial line discipline");
70                 close(fd);
71                 return -1;
72         }
73
74         /* Switch TTY to raw mode */
75         memset(&ti, 0, sizeof(ti));
76         cfmakeraw(&ti);
77
78         ti.c_cflag |= (B115200 | CLOCAL | CREAD);
79
80         /* Set flow control */
81         ti.c_cflag |= CRTSCTS;
82
83         if (tcsetattr(fd, TCSANOW, &ti) < 0) {
84                 perror("Failed to set serial port settings");
85                 close(fd);
86                 return -1;
87         }
88
89         if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
90                 perror("Failed set serial line discipline");
91                 close(fd);
92                 return -1;
93         }
94
95         printf("Switched line discipline from %d to %d\n", saved_ldisc, ldisc);
96
97         return fd;
98 }
99
100 static void local_version_callback(const void *data, uint8_t size,
101                                                         void *user_data)
102 {
103         const struct bt_hci_rsp_read_local_version *rsp = data;
104
105         printf("Manufacturer: %u\n", le16_to_cpu(rsp->manufacturer));
106 }
107
108 static int attach_proto(const char *path, unsigned int proto,
109                                                 unsigned int flags)
110 {
111         int fd, dev_id;
112
113         fd = open_serial(path);
114         if (fd < 0)
115                 return -1;
116
117         if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
118                 perror("Failed to set flags");
119                 close(fd);
120                 return -1;
121         }
122
123         if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
124                 perror("Failed to set protocol");
125                 close(fd);
126                 return -1;
127         }
128
129         dev_id = ioctl(fd, HCIUARTGETDEVICE);
130         if (dev_id < 0) {
131                 perror("Failed to get device id");
132                 close(fd);
133                 return -1;
134         }
135
136         printf("Device index %d attached\n", dev_id);
137
138         if (flags & (1 << HCI_UART_RAW_DEVICE)) {
139                 unsigned int attempts = 6;
140                 struct bt_hci *hci;
141
142                 while (attempts-- > 0) {
143                         hci = bt_hci_new_user_channel(dev_id);
144                         if (hci)
145                                 break;
146
147                         usleep(250 * 1000);
148                 }
149
150                 if (!hci) {
151                         fprintf(stderr, "Failed to open HCI user channel\n");
152                         close(fd);
153                         return -1;
154                 }
155
156                 bt_hci_send(hci, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
157                                         local_version_callback, hci,
158                                         (bt_hci_destroy_func_t) bt_hci_unref);
159         }
160
161         return fd;
162 }
163
164 static void uart_callback(int fd, uint32_t events, void *user_data)
165 {
166         printf("UART callback handling\n");
167 }
168
169 static void signal_callback(int signum, void *user_data)
170 {
171         static bool terminated = false;
172
173         switch (signum) {
174         case SIGINT:
175         case SIGTERM:
176                 if (!terminated) {
177                         mainloop_quit();
178                         terminated = true;
179                 }
180                 break;
181         }
182 }
183 static void usage(void)
184 {
185         printf("btattach - Bluetooth serial utility\n"
186                 "Usage:\n");
187         printf("\tbtattach [options]\n");
188         printf("options:\n"
189                 "\t-B, --bredr <device>   Attach BR/EDR controller\n"
190                 "\t-A, --amp <device>     Attach AMP controller\n"
191                 "\t-P, --protocol <proto> Specify protocol type\n"
192                 "\t-h, --help             Show help options\n");
193 }
194
195 static const struct option main_options[] = {
196         { "bredr",    required_argument, NULL, 'B' },
197         { "amp",      required_argument, NULL, 'A' },
198         { "protocol", required_argument, NULL, 'P' },
199         { "version",  no_argument,       NULL, 'v' },
200         { "help",     no_argument,       NULL, 'h' },
201         { }
202 };
203
204 static const struct {
205         const char *name;
206         unsigned int id;
207 } proto_table[] = {
208         { "h4",    HCI_UART_H4    },
209         { "bcsp",  HCI_UART_BCSP  },
210         { "3wire", HCI_UART_3WIRE },
211         { "h4ds",  HCI_UART_H4DS  },
212         { "ll",    HCI_UART_LL    },
213         { "ath3k", HCI_UART_ATH3K },
214         { "intel", HCI_UART_INTEL },
215         { "bcm",   HCI_UART_BCM   },
216         { "qca",   HCI_UART_QCA   },
217         { }
218 };
219
220 int main(int argc, char *argv[])
221 {
222         const char *bredr_path = NULL, *amp_path = NULL, *proto = NULL;
223         bool raw_device = false;
224         sigset_t mask;
225         int exit_status, count = 0, proto_id = HCI_UART_H4;
226
227         for (;;) {
228                 int opt;
229
230                 opt = getopt_long(argc, argv, "B:A:P:Rvh",
231                                                 main_options, NULL);
232                 if (opt < 0)
233                         break;
234
235                 switch (opt) {
236                 case 'B':
237                         bredr_path = optarg;
238                         break;
239                 case 'A':
240                         amp_path = optarg;
241                         break;
242                 case 'P':
243                         proto = optarg;
244                         break;
245                 case 'R':
246                         raw_device = true;
247                         break;
248                 case 'v':
249                         printf("%s\n", VERSION);
250                         return EXIT_SUCCESS;
251                 case 'h':
252                         usage();
253                         return EXIT_SUCCESS;
254                 default:
255                         return EXIT_FAILURE;
256                 }
257         }
258
259         if (argc - optind > 0) {
260                 fprintf(stderr, "Invalid command line parameters\n");
261                 return EXIT_FAILURE;
262         }
263
264         mainloop_init();
265
266         sigemptyset(&mask);
267         sigaddset(&mask, SIGINT);
268         sigaddset(&mask, SIGTERM);
269
270         mainloop_set_signal(&mask, signal_callback, NULL, NULL);
271
272         if (proto) {
273                 unsigned int i;
274
275                 for (i = 0; proto_table[i].name; i++) {
276                         if (!strcmp(proto_table[i].name, proto)) {
277                                 proto_id = proto_table[i].id;
278                                 break;
279                         }
280                 }
281
282                 if (!proto_table[i].name) {
283                         fprintf(stderr, "Invalid protocol\n");
284                         return EXIT_FAILURE;
285                 }
286         }
287
288         if (bredr_path) {
289                 unsigned long flags;
290                 int fd;
291
292                 printf("Attaching BR/EDR controller to %s\n", bredr_path);
293
294                 flags = (1 << HCI_UART_RESET_ON_INIT);
295
296                 if (raw_device)
297                         flags = (1 << HCI_UART_RAW_DEVICE);
298
299                 fd = attach_proto(bredr_path, proto_id, flags);
300                 if (fd >= 0) {
301                         mainloop_add_fd(fd, 0, uart_callback, NULL, NULL);
302                         count++;
303                 }
304         }
305
306         if (amp_path) {
307                 unsigned long flags;
308                 int fd;
309
310                 printf("Attaching AMP controller to %s\n", amp_path);
311
312                 flags = (1 << HCI_UART_RESET_ON_INIT) |
313                         (1 << HCI_UART_CREATE_AMP);
314
315                 if (raw_device)
316                         flags = (1 << HCI_UART_RAW_DEVICE);
317
318                 fd = attach_proto(amp_path, proto_id, flags);
319                 if (fd >= 0) {
320                         mainloop_add_fd(fd, 0, uart_callback, NULL, NULL);
321                         count++;
322                 }
323         }
324
325         if (count < 1) {
326                 fprintf(stderr, "No controller attached\n");
327                 return EXIT_FAILURE;
328         }
329
330         exit_status = mainloop_run();
331
332         return exit_status;
333 }