OSDN Git Service

bluedroid: fix bluetooth rfkill id issues
[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 sz;
86     int fd = -1;
87     int ret = -1;
88     char buffer;
89
90     if (rfkill_state_path[0] == '\0') {
91         if (init_rfkill()) goto out;
92     }
93
94     fd = open(rfkill_state_path, O_RDONLY);
95     if (fd < 0) {
96         LOGE("open(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
97              errno);
98         goto out;
99     }
100     sz = read(fd, &buffer, 1);
101     if (sz != 1) {
102         LOGE("read(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
103              errno);
104         goto out;
105     }
106
107     switch (buffer) {
108     case '1':
109         ret = 1;
110         break;
111     case '0':
112         ret = 0;
113         break;
114     }
115
116 out:
117     if (fd >= 0) close(fd);
118     return ret;
119 }
120
121 static int set_bluetooth_power(int on) {
122     int sz;
123     int fd = -1;
124     int ret = -1;
125     const char buffer = (on ? '1' : '0');
126
127     if (rfkill_state_path[0] == '\0') {
128         if (init_rfkill()) goto out;
129     }
130
131     fd = open(rfkill_state_path, O_WRONLY);
132     if (fd < 0) {
133         LOGE("open(%s) for write failed: %s (%d)", rfkill_state_path,
134              strerror(errno), errno);
135         goto out;
136     }
137     sz = write(fd, &buffer, 1);
138     if (sz < 0) {
139         LOGE("write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
140              errno);
141         goto out;
142     }
143     ret = 0;
144
145 out:
146     if (fd >= 0) close(fd);
147     return ret;
148 }
149
150 static inline int create_hci_sock() {
151     int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
152     if (sk < 0) {
153         LOGE("Failed to create bluetooth hci socket: %s (%d)",
154              strerror(errno), errno);
155     }
156     return sk;
157 }
158
159 int bt_enable() {
160     LOGV(__FUNCTION__);
161
162     int ret = -1;
163     int hci_sock = -1;
164     int attempt;
165
166     if (set_bluetooth_power(1) < 0) goto out;
167
168     LOGI("Starting hciattach daemon");
169     if (property_set("ctl.start", "hciattach") < 0) {
170         LOGE("Failed to start hciattach");
171         set_bluetooth_power(0);
172         goto out;
173     }
174
175     // Try for 10 seconds, this can only succeed once hciattach has sent the
176     // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
177     for (attempt = 1000; attempt > 0;  attempt--) {
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         close(hci_sock);
185         usleep(10000);  // 10 ms retry delay
186     }
187     if (attempt == 0) {
188         LOGE("%s: Timeout waiting for HCI device to come up", __FUNCTION__);
189         set_bluetooth_power(0);
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         set_bluetooth_power(0);
197         goto out;
198     }
199
200     ret = 0;
201
202 out:
203     if (hci_sock >= 0) close(hci_sock);
204     return ret;
205 }
206
207 int bt_disable() {
208     LOGV(__FUNCTION__);
209
210     int ret = -1;
211     int hci_sock = -1;
212
213     LOGI("Stopping bluetoothd deamon");
214     if (property_set("ctl.stop", "bluetoothd") < 0) {
215         LOGE("Error stopping bluetoothd");
216         goto out;
217     }
218     usleep(HCID_STOP_DELAY_USEC);
219
220     hci_sock = create_hci_sock();
221     if (hci_sock < 0) goto out;
222     ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
223
224     LOGI("Stopping hciattach deamon");
225     if (property_set("ctl.stop", "hciattach") < 0) {
226         LOGE("Error stopping hciattach");
227         goto out;
228     }
229
230     if (set_bluetooth_power(0) < 0) {
231         goto out;
232     }
233     ret = 0;
234
235 out:
236     rfkill_state_path[0] = '\0';
237
238     if (hci_sock >= 0) close(hci_sock);
239     return ret;
240 }
241
242 int bt_is_enabled() {
243     LOGV(__FUNCTION__);
244
245     int hci_sock = -1;
246     int ret = -1;
247     struct hci_dev_info dev_info;
248
249
250     // Check power first
251     ret = check_bluetooth_power();
252     if (ret == -1 || ret == 0) goto out;
253
254     ret = -1;
255
256     // Power is on, now check if the HCI interface is up
257     hci_sock = create_hci_sock();
258     if (hci_sock < 0) goto out;
259
260     dev_info.dev_id = HCI_DEV_ID;
261     if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
262         ret = 0;
263         goto out;
264     }
265
266     ret = hci_test_bit(HCI_UP, &dev_info.flags);
267
268 out:
269     if (hci_sock >= 0) close(hci_sock);
270     return ret;
271 }
272
273 int ba2str(const bdaddr_t *ba, char *str) {
274     return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
275                 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
276 }
277
278 int str2ba(const char *str, bdaddr_t *ba) {
279     int i;
280     for (i = 5; i >= 0; i--) {
281         ba->b[i] = (uint8_t) strtoul(str, &str, 16);
282         str++;
283     }
284     return 0;
285 }