1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "bluedroid"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26
27 #include <cutils/log.h>
28 #include <cutils/properties.h>
29
30 #include <bluetooth/bluetooth.h>
31 #include <bluetooth/hci.h>
32 #include <bluetooth/hci_lib.h>
33
34 #include <bluedroid/bluetooth.h>
35
36 #ifndef HCI_DEV_ID
37 #define HCI_DEV_ID 0
38 #endif
39
40 #define HCID_STOP_DELAY_USEC 500000
41
42 #define MIN(x,y) (((x)<(y))?(x):(y))
43
44
45 static int rfkill_id = -1;
46 static char *rfkill_state_path = NULL;
47
48 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
init_rfkill()49 static int init_rfkill() {
50 char path[64];
51 char buf[16];
52 int fd;
53 int sz;
54 int id;
55 for (id = 0; ; id++) {
56 snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
57 fd = open(path, O_RDONLY);
58 if (fd < 0) {
59 ALOGW("open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
60 return -1;
61 }
62 sz = read(fd, &buf, sizeof(buf));
63 close(fd);
64 if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) {
65 rfkill_id = id;
66 break;
67 }
68 }
69
70 asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
71 return 0;
72 }
73
check_bluetooth_power()74 static int check_bluetooth_power() {
75 int sz;
76 int fd = -1;
77 int ret = -1;
78 char buffer;
79
80 if (rfkill_id == -1) {
81 if (init_rfkill()) goto out;
82 }
83
84 fd = open(rfkill_state_path, O_RDONLY);
85 if (fd < 0) {
86 ALOGE("open(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
87 errno);
88 goto out;
89 }
90 sz = read(fd, &buffer, 1);
91 if (sz != 1) {
92 ALOGE("read(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
93 errno);
94 goto out;
95 }
96
97 switch (buffer) {
98 case '1':
99 ret = 1;
100 break;
101 case '0':
102 ret = 0;
103 break;
104 }
105
106 out:
107 if (fd >= 0) close(fd);
108 return ret;
109 }
110
set_bluetooth_power(int on)111 static int set_bluetooth_power(int on) {
112 int sz;
113 int fd = -1;
114 int ret = -1;
115 const char buffer = (on ? '1' : '0');
116
117 if (rfkill_id == -1) {
118 if (init_rfkill()) goto out;
119 }
120
121 fd = open(rfkill_state_path, O_WRONLY);
122 if (fd < 0) {
123 ALOGE("open(%s) for write failed: %s (%d)", rfkill_state_path,
124 strerror(errno), errno);
125 goto out;
126 }
127 sz = write(fd, &buffer, 1);
128 if (sz < 0) {
129 ALOGE("write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
130 errno);
131 goto out;
132 }
133 ret = 0;
134
135 out:
136 if (fd >= 0) close(fd);
137 return ret;
138 }
139 #endif
140
create_hci_sock()141 static inline int create_hci_sock() {
142 int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
143 if (sk < 0) {
144 ALOGE("Failed to create bluetooth hci socket: %s (%d)",
145 strerror(errno), errno);
146 }
147 return sk;
148 }
149
bt_enable()150 int bt_enable() {
151 ALOGV(__FUNCTION__);
152
153 int ret = -1;
154 int hci_sock = -1;
155 int attempt;
156
157 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
158 if (set_bluetooth_power(1) < 0) goto out;
159 #endif
160
161 #ifndef BLUETOOTH_HCIATTACH_USING_PROPERTY
162 ALOGI("Starting hciattach daemon");
163 if (property_set("ctl.start", "hciattach") < 0)
164 #else
165 ALOGI("Enable hci tranport");
166 if (property_set("bluetooth.hciattach", "true") < 0)
167 #endif
168 {
169 ALOGE("Failed to start hciattach");
170 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
171 set_bluetooth_power(0);
172 #endif
173 goto out;
174 }
175
176 // Try for 10 seconds, this can only succeed once hciattach has sent the
177 // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
178 for (attempt = 100; attempt > 0; attempt--) {
179 hci_sock = create_hci_sock();
180 if (hci_sock < 0) goto out;
181
182 ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID);
183
184 if (!ret) {
185 break;
186 } else if (errno == EALREADY) {
187 ALOGW("Bluetoothd already started, unexpectedly!");
188 break;
189 }
190
191 ALOGI("%s: ioctl(%d, HCIDEVUP, HCI_DEV_ID) failed: %s (%d)",
192 __FUNCTION__, hci_sock, strerror(errno), errno);
193
194 close(hci_sock);
195 usleep(100 * 1000); // 100 ms retry delay
196 }
197 if (attempt == 0) {
198 ALOGE("%s: Timeout waiting for HCI device to come up, error- %d, ",
199 __FUNCTION__, ret);
200 if (property_set("ctl.stop", "hciattach") < 0) {
201 ALOGE("Error stopping hciattach");
202 }
203 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
204 set_bluetooth_power(0);
205 #endif
206 goto out;
207 }
208
209 ALOGI("Starting bluetoothd deamon");
210 if (property_set("ctl.start", "bluetoothd") < 0) {
211 ALOGE("Failed to start bluetoothd");
212 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
213 set_bluetooth_power(0);
214 #endif
215 goto out;
216 }
217
218 ret = 0;
219
220 out:
221 if (hci_sock >= 0) close(hci_sock);
222 return ret;
223 }
224
bt_disable()225 int bt_disable() {
226 ALOGV(__FUNCTION__);
227
228 int ret = -1;
229 int hci_sock = -1;
230
231 ALOGI("Stopping bluetoothd deamon");
232 if (property_set("ctl.stop", "bluetoothd") < 0) {
233 ALOGE("Error stopping bluetoothd");
234 goto out;
235 }
236 usleep(HCID_STOP_DELAY_USEC);
237
238 hci_sock = create_hci_sock();
239 if (hci_sock < 0) goto out;
240 ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
241
242 #ifndef BLUETOOTH_HCIATTACH_USING_PROPERTY
243 ALOGI("Stopping hciattach deamon");
244 if (property_set("ctl.stop", "hciattach") < 0)
245 #else
246 ALOGI("Disable hci tranport");
247 if (property_set("bluetooth.hciattach", "false") < 0)
248 #endif
249 {
250 ALOGE("Error stopping hciattach");
251 goto out;
252 }
253
254 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
255 if (set_bluetooth_power(0) < 0) {
256 goto out;
257 }
258 #endif
259 ret = 0;
260
261 out:
262 if (hci_sock >= 0) close(hci_sock);
263 return ret;
264 }
265
bt_is_enabled()266 int bt_is_enabled() {
267 ALOGV(__FUNCTION__);
268
269 int hci_sock = -1;
270 int ret = -1;
271 struct hci_dev_info dev_info;
272
273
274 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
275 // Check power first
276 ret = check_bluetooth_power();
277 if (ret == -1 || ret == 0) goto out;
278 #endif
279
280 ret = -1;
281
282 // Power is on, now check if the HCI interface is up
283 hci_sock = create_hci_sock();
284 if (hci_sock < 0) goto out;
285
286 dev_info.dev_id = HCI_DEV_ID;
287 if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
288 ret = 0;
289 goto out;
290 }
291
292 if (dev_info.flags & (1 << (HCI_UP & 31))) {
293 ret = 1;
294 } else {
295 ret = 0;
296 }
297
298 out:
299 if (hci_sock >= 0) close(hci_sock);
300 return ret;
301 }
302
ba2str(const bdaddr_t * ba,char * str)303 int ba2str(const bdaddr_t *ba, char *str) {
304 return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
305 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
306 }
307
str2ba(const char * str,bdaddr_t * ba)308 int str2ba(const char *str, bdaddr_t *ba) {
309 int i;
310 for (i = 5; i >= 0; i--) {
311 ba->b[i] = (uint8_t) strtoul(str, (char **) &str, 16);
312 str++;
313 }
314 return 0;
315 }
316