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 <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25
26 #include <cutils/log.h>
27 #include <cutils/properties.h>
28
29 #include <bluetooth/bluetooth.h>
30 #include <bluetooth/hci.h>
31 #include <bluetooth/hci_lib.h>
32
33 #include <bluedroid/bluetooth.h>
34
35 #ifndef HCI_DEV_ID
36 #define HCI_DEV_ID 0
37 #endif
38
39 #define HCID_START_DELAY_SEC 3
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
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 LOGW("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 LOGE("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 LOGE("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 LOGE("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 LOGE("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
create_hci_sock()140 static inline int create_hci_sock() {
141 int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
142 if (sk < 0) {
143 LOGE("Failed to create bluetooth hci socket: %s (%d)",
144 strerror(errno), errno);
145 }
146 return sk;
147 }
148
bt_enable()149 int bt_enable() {
150 LOGV(__FUNCTION__);
151
152 int ret = -1;
153 int hci_sock = -1;
154 int attempt;
155
156 if (set_bluetooth_power(1) < 0) goto out;
157
158 LOGI("Starting hciattach daemon");
159 if (property_set("ctl.start", "hciattach") < 0) {
160 LOGE("Failed to start hciattach");
161 goto out;
162 }
163
164 // Try for 10 seconds, this can only succeed once hciattach has sent the
165 // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
166 for (attempt = 1000; attempt > 0; attempt--) {
167 hci_sock = create_hci_sock();
168 if (hci_sock < 0) goto out;
169
170 if (!ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID)) {
171 break;
172 }
173 close(hci_sock);
174 usleep(10000); // 10 ms retry delay
175 }
176 if (attempt == 0) {
177 LOGE("%s: Timeout waiting for HCI device to come up", __FUNCTION__);
178 goto out;
179 }
180
181 LOGI("Starting bluetoothd deamon");
182 if (property_set("ctl.start", "bluetoothd") < 0) {
183 LOGE("Failed to start bluetoothd");
184 goto out;
185 }
186 sleep(HCID_START_DELAY_SEC);
187
188 ret = 0;
189
190 out:
191 if (hci_sock >= 0) close(hci_sock);
192 return ret;
193 }
194
bt_disable()195 int bt_disable() {
196 LOGV(__FUNCTION__);
197
198 int ret = -1;
199 int hci_sock = -1;
200
201 LOGI("Stopping bluetoothd deamon");
202 if (property_set("ctl.stop", "bluetoothd") < 0) {
203 LOGE("Error stopping bluetoothd");
204 goto out;
205 }
206 usleep(HCID_STOP_DELAY_USEC);
207
208 hci_sock = create_hci_sock();
209 if (hci_sock < 0) goto out;
210 ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
211
212 LOGI("Stopping hciattach deamon");
213 if (property_set("ctl.stop", "hciattach") < 0) {
214 LOGE("Error stopping hciattach");
215 goto out;
216 }
217
218 if (set_bluetooth_power(0) < 0) {
219 goto out;
220 }
221 ret = 0;
222
223 out:
224 if (hci_sock >= 0) close(hci_sock);
225 return ret;
226 }
227
bt_is_enabled()228 int bt_is_enabled() {
229 LOGV(__FUNCTION__);
230
231 int hci_sock = -1;
232 int ret = -1;
233 struct hci_dev_info dev_info;
234
235
236 // Check power first
237 ret = check_bluetooth_power();
238 if (ret == -1 || ret == 0) goto out;
239
240 ret = -1;
241
242 // Power is on, now check if the HCI interface is up
243 hci_sock = create_hci_sock();
244 if (hci_sock < 0) goto out;
245
246 dev_info.dev_id = HCI_DEV_ID;
247 if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
248 ret = 0;
249 goto out;
250 }
251
252 ret = hci_test_bit(HCI_UP, &dev_info.flags);
253
254 out:
255 if (hci_sock >= 0) close(hci_sock);
256 return ret;
257 }
258
ba2str(const bdaddr_t * ba,char * str)259 int ba2str(const bdaddr_t *ba, char *str) {
260 return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
261 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
262 }
263
str2ba(const char * str,bdaddr_t * ba)264 int str2ba(const char *str, bdaddr_t *ba) {
265 int i;
266 for (i = 5; i >= 0; i--) {
267 ba->b[i] = (uint8_t) strtoul(str, &str, 16);
268 str++;
269 }
270 return 0;
271 }
272