OSDN Git Service

11b0aa76df98db6340ffb8b6f0639e59b5e8f6f3
[android-x86/system-bluetooth.git] / bluedroid / bluetooth.c
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 <dirent.h>
20 #include <errno.h>
21 #include <fcntl.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 const char *sysrfkill = "/sys/class/rfkill";
46 static char rfkill_state_path[64] = "";
47
48
49 static int init_rfkill() {
50     char path[64];
51     char buf[16];
52     int fd;
53     int sz;
54     struct dirent *entry;
55     DIR *sysdir = opendir(sysrfkill);
56
57     if (sysdir == NULL) {
58         LOGE("opendir failed: %s (%d)\n", strerror(errno), errno);
59         return -1;
60     }
61
62     while ((entry = readdir(sysdir))) {
63         if (entry->d_name[0] == '.')
64             continue;
65         snprintf(path, sizeof(path), "%s/%s/type", sysrfkill, entry->d_name);
66         fd = open(path, O_RDONLY);
67         if (fd < 0) {
68             LOGW("open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
69             continue;
70         }
71         sz = read(fd, &buf, sizeof(buf));
72         close(fd);
73         if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) {
74             snprintf(rfkill_state_path, sizeof(rfkill_state_path),
75                     "%s/%s/state", sysrfkill, entry->d_name);
76             break;
77         }
78     }
79
80     closedir(sysdir);
81     return rfkill_state_path[0] ? 0 : -1;
82 }
83
84 static int check_bluetooth_power() {
85     int fd = -1;
86     int ret = -1;
87     char buffer;
88
89     if (rfkill_state_path[0] == '\0') {
90         if (init_rfkill()) goto out;
91     }
92
93     fd = open(rfkill_state_path, O_RDONLY);
94     if (fd < 0) {
95         LOGE("open(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
96              errno);
97         goto out;
98     }
99     if (read(fd, &buffer, 1) != 1) {
100         LOGE("read(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
101              errno);
102         goto out;
103     }
104
105     switch (buffer) {
106     case '1':
107         ret = 1;
108         break;
109     case '0':
110         ret = 0;
111         break;
112     }
113
114 out:
115     if (fd >= 0) close(fd);
116     return ret;
117 }
118
119 static int set_bluetooth_power(int on) {
120     int fd = -1;
121     int ret = check_bluetooth_power();
122     const char buffer = (on ? '1' : '0');
123
124     if (ret < 0)
125         return ret;
126     else if (ret == on)
127         return 0;
128
129     fd = open(rfkill_state_path, O_WRONLY);
130     if (fd < 0) {
131         LOGE("open(%s) for write failed: %s (%d)", rfkill_state_path,
132              strerror(errno), errno);
133         goto out;
134     }
135     if (write(fd, &buffer, 1) != 1) {
136         LOGE("write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
137              errno);
138         goto out;
139     }
140     ret = 0;
141
142 out:
143     if (fd >= 0) close(fd);
144     return ret;
145 }
146
147 static int create_hci_sock() {
148     int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
149     if (sk < 0) {
150         LOGE("Failed to create bluetooth hci socket: %s (%d)",
151              strerror(errno), errno);
152     }
153     return sk;
154 }
155
156 int bt_enable() {
157     LOGV(__FUNCTION__);
158
159     int ret = -1;
160     int hci_sock = -1;
161     int attempt;
162
163     LOGI("Starting hciattach daemon");
164     if (property_set("ctl.start", "hciattach") < 0) {
165         LOGE("Failed to start hciattach");
166         goto out;
167     }
168
169     // Try for 10 seconds, this can only succeed once hciattach has sent the
170     // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
171     for (attempt = 10; attempt > 0; --attempt) {
172         int res = set_bluetooth_power(1);
173         sleep(1);
174         if (res < 0) {
175             bt_disable();
176             continue;
177         }
178         hci_sock = create_hci_sock();
179         if (hci_sock < 0) goto out;
180
181         if (!ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID))
182             break;
183
184         LOGE("ioctl failed: %s (%d)", strerror(errno), errno);
185         close(hci_sock);
186         usleep(10000);  // 10 ms retry delay
187     }
188     if (attempt == 0) {
189         LOGE("%s: Timeout waiting for HCI device to come up", __FUNCTION__);
190         goto out;
191     }
192
193     LOGI("Starting bluetoothd deamon");
194     if (property_set("ctl.start", "bluetoothd") < 0) {
195         LOGE("Failed to start bluetoothd");
196         goto out;
197     }
198
199     ret = 0;
200
201 out:
202     if (hci_sock >= 0) close(hci_sock);
203     return ret;
204 }
205
206 int bt_disable() {
207     LOGV(__FUNCTION__);
208
209     int ret = -1;
210     int hci_sock = -1;
211
212     LOGI("Stopping bluetoothd deamon");
213     if (property_set("ctl.stop", "bluetoothd") < 0) {
214         LOGE("Error stopping bluetoothd");
215         goto out;
216     }
217     usleep(HCID_STOP_DELAY_USEC);
218
219     hci_sock = create_hci_sock();
220     if (hci_sock < 0) goto out;
221     ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
222
223     LOGI("Stopping hciattach deamon");
224     if (property_set("ctl.stop", "hciattach") < 0) {
225         LOGE("Error stopping hciattach");
226         goto out;
227     }
228
229     if (set_bluetooth_power(0) < 0) {
230         goto out;
231     }
232     ret = 0;
233
234 out:
235     rfkill_state_path[0] = '\0';
236
237     if (hci_sock >= 0) close(hci_sock);
238     return ret;
239 }
240
241 int bt_is_enabled() {
242     LOGV(__FUNCTION__);
243
244     int hci_sock = -1;
245     int ret = -1;
246     struct hci_dev_info dev_info;
247
248
249     // Check power first
250     ret = check_bluetooth_power();
251     if (ret == -1 || ret == 0) goto out;
252
253     ret = -1;
254
255     // Power is on, now check if the HCI interface is up
256     hci_sock = create_hci_sock();
257     if (hci_sock < 0) goto out;
258
259     dev_info.dev_id = HCI_DEV_ID;
260     if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
261         ret = 0;
262         goto out;
263     }
264
265     ret = hci_test_bit(HCI_UP, &dev_info.flags);
266
267 out:
268     if (hci_sock >= 0) close(hci_sock);
269     return ret;
270 }
271
272 int ba2str(const bdaddr_t *ba, char *str) {
273     return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
274                 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
275 }
276
277 int str2ba(const char *str, bdaddr_t *ba) {
278     int i;
279     for (i = 5; i >= 0; i--) {
280         ba->b[i] = (uint8_t) strtoul(str, &str, 16);
281         str++;
282     }
283     return 0;
284 }