Home | History | Annotate | Download | only in bluedroid
      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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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