bluetooth.c revision 6c2d13d0c3a4505fdac56ae8d537a68218e072f1
1/*
2 * Copyright (C) 2008 Google Inc.
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   5
40#define HCID_STOP_DELAY_USEC 500000
41
42#define MIN(x,y) (((x)<(y))?(x):(y))
43
44#define USE_UGLY_POWER_INTERFACE 1
45#if USE_UGLY_POWER_INTERFACE
46
47#define BLUETOOTH_POWER_PATH "/sys/module/board_trout/parameters/bluetooth_power_on"
48
49static int set_bluetooth_power(int on) {
50    int ret = -1;
51    int sz;
52    const char buffer = (on ? 'Y' : 'N');
53    int fd = open(BLUETOOTH_POWER_PATH, O_WRONLY);
54
55    if (fd == -1) {
56        LOGE("Can't open %s for write: %s (%d)", BLUETOOTH_POWER_PATH,
57             strerror(errno), errno);
58        goto out;
59    }
60    sz = write(fd, &buffer, 1);
61    if (sz != 1) {
62        LOGE("Can't write to %s: %s (%d)", BLUETOOTH_POWER_PATH,
63             strerror(errno), errno);
64        goto out;
65    }
66    ret = 0;
67
68out:
69    if (fd >= 0) close(fd);
70    return ret;
71}
72
73static int check_bluetooth_power() {
74    int ret = -1;
75    int sz;
76    char buffer;
77    int fd = open(BLUETOOTH_POWER_PATH, O_RDONLY);
78
79    if (fd == -1) {
80        LOGE("Can't open %s for read: %s (%d)", BLUETOOTH_POWER_PATH,
81             strerror(errno), errno);
82        goto out;
83    }
84    sz = read(fd, &buffer, 1);
85    if (sz != 1) {
86        LOGE("Can't read from %s: %s (%d)", BLUETOOTH_POWER_PATH,
87             strerror(errno), errno);
88        goto out;
89    }
90
91    switch (buffer) {
92    case 'Y':
93        ret = 1;
94        break;
95    case 'N':
96        ret = 0;
97        break;
98    }
99
100out:
101    if (fd >= 0) close(fd);
102    return ret;
103}
104
105#else
106
107static int rfkill_id = -1;
108static char *rfkill_state_path = NULL;
109
110
111static int init_rfkill() {
112    char path[64];
113    char buf[16];
114    int fd;
115    int sz;
116    int id;
117    for (id = 0; ; id++) {
118        snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
119        fd = open(path, O_RDONLY);
120        if (fd < 0) {
121            LOGW("open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
122            return -1;
123        }
124        sz = read(fd, &buf, sizeof(buf));
125        close(fd);
126        if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) {
127            rfkill_id = id;
128            break;
129        }
130    }
131
132    asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
133    return 0;
134}
135
136static int check_bluetooth_power() {
137    int sz;
138    int fd = -1;
139    int ret = -1;
140    char buffer;
141
142    if (rfkill_id == -1) {
143        if (init_rfkill()) goto out;
144    }
145
146    fd = open(rfkill_state_path, O_RDONLY);
147    if (fd < 0) {
148        LOGE("open(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
149             errno);
150        goto out;
151    }
152    sz = read(fd, &buffer, 1);
153    if (sz != 1) {
154        LOGE("read(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
155             errno);
156        goto out;
157    }
158
159    switch (buffer) {
160    case '1':
161        ret = 1;
162        break;
163    case '0':
164        ret = 0;
165        break;
166    }
167
168out:
169    if (fd >= 0) close(fd);
170    return ret;
171}
172
173static int set_bluetooth_power(int on) {
174    int sz;
175    int fd = -1;
176    int ret = -1;
177    const char buffer = (on ? '1' : '0');
178
179    if (rfkill_id == -1) {
180        if (init_rfkill()) goto out;
181    }
182
183    fd = open(rfkill_state_path, O_WRONLY);
184    if (fd < 0) {
185        LOGE("open(%s) for write failed: %s (%d)", rfkill_state_path,
186             strerror(errno), errno);
187        goto out;
188    }
189    sz = write(fd, &buffer, 1);
190    if (sz < 0) {
191        LOGE("write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
192             errno);
193        goto out;
194    }
195    ret = 0;
196
197out:
198    if (fd >= 0) close(fd);
199    return ret;
200}
201#endif
202
203static inline int create_hci_sock() {
204    int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
205    if (sk < 0) {
206        LOGE("Failed to create bluetooth hci socket: %s (%d)",
207             strerror(errno), errno);
208    }
209    return sk;
210}
211
212int bt_enable() {
213    LOGV(__FUNCTION__);
214
215    int ret = -1;
216    int hci_sock = -1;
217    int attempt;
218
219    if (set_bluetooth_power(1) < 0) goto out;
220
221    LOGI("Starting hciattach daemon");
222    if (property_set("ctl.start", "hciattach") < 0) {
223        LOGE("Failed to start hciattach");
224        goto out;
225    }
226
227    // Try for 10 seconds, this can only succeed once hciattach has sent the
228    // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
229    for (attempt = 1000; attempt > 0;  attempt--) {
230        hci_sock = create_hci_sock();
231        if (hci_sock < 0) goto out;
232
233        if (!ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID)) {
234            break;
235        }
236        close(hci_sock);
237        usleep(10000);  // 10 ms retry delay
238    }
239    if (attempt == 0) {
240        LOGE("%s: Timeout waiting for HCI device to come up", __FUNCTION__);
241        goto out;
242    }
243
244    LOGI("Starting hcid deamon");
245    if (property_set("ctl.start", "hcid") < 0) {
246        LOGE("Failed to start hcid");
247        goto out;
248    }
249    sleep(HCID_START_DELAY_SEC);
250
251    ret = 0;
252
253out:
254    if (hci_sock >= 0) close(hci_sock);
255    return ret;
256}
257
258int bt_disable() {
259    LOGV(__FUNCTION__);
260
261    int ret = -1;
262    int hci_sock = -1;
263
264    LOGI("Stopping hcid deamon");
265    if (property_set("ctl.stop", "hcid") < 0) {
266        LOGE("Error stopping hcid");
267        goto out;
268    }
269    usleep(HCID_STOP_DELAY_USEC);
270
271    hci_sock = create_hci_sock();
272    if (hci_sock < 0) goto out;
273    ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
274
275    LOGI("Stopping hciattach deamon");
276    if (property_set("ctl.stop", "hciattach") < 0) {
277        LOGE("Error stopping hciattach");
278        goto out;
279    }
280
281    if (set_bluetooth_power(0) < 0) {
282        goto out;
283    }
284    ret = 0;
285
286out:
287    if (hci_sock >= 0) close(hci_sock);
288    return ret;
289}
290
291int bt_is_enabled() {
292    LOGV(__FUNCTION__);
293
294    int hci_sock = -1;
295    int ret = -1;
296    struct hci_dev_info dev_info;
297
298
299    // Check power first
300    ret = check_bluetooth_power();
301    if (ret == -1 || ret == 0) goto out;
302
303    ret = -1;
304
305    // Power is on, now check if the HCI interface is up
306    hci_sock = create_hci_sock();
307    if (hci_sock < 0) goto out;
308
309    dev_info.dev_id = HCI_DEV_ID;
310    if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
311        ret = 0;
312        goto out;
313    }
314
315    ret = hci_test_bit(HCI_UP, &dev_info.flags);
316
317out:
318    if (hci_sock >= 0) close(hci_sock);
319    return ret;
320}
321