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 <stdlib.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 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             ALOGW("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         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("Failed to create bluetooth hci socket: %s (%d)",
    144              strerror(errno), errno);
    145     }
    146     return sk;
    147 }
    148 
    149 int bt_enable() {
    150     ALOGV(__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     ALOGI("Starting hciattach daemon");
    159     if (property_set("ctl.start", "hciattach") < 0) {
    160         ALOGE("Failed to start hciattach");
    161         set_bluetooth_power(0);
    162         goto out;
    163     }
    164 
    165     // Try for 10 seconds, this can only succeed once hciattach has sent the
    166     // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
    167     for (attempt = 1000; attempt > 0;  attempt--) {
    168         hci_sock = create_hci_sock();
    169         if (hci_sock < 0) goto out;
    170 
    171         ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID);
    172 
    173         ALOGI("bt_enable: ret: %d, errno: %d", ret, errno);
    174         if (!ret) {
    175             break;
    176         } else if (errno == EALREADY) {
    177             ALOGW("Bluetoothd already started, unexpectedly!");
    178             break;
    179         }
    180 
    181         close(hci_sock);
    182         usleep(100000);  // 100 ms retry delay
    183     }
    184     if (attempt == 0) {
    185         ALOGE("%s: Timeout waiting for HCI device to come up, error- %d, ",
    186             __FUNCTION__, ret);
    187         if (property_set("ctl.stop", "hciattach") < 0) {
    188             ALOGE("Error stopping hciattach");
    189         }
    190         set_bluetooth_power(0);
    191         goto out;
    192     }
    193 
    194     ALOGI("Starting bluetoothd deamon");
    195     if (property_set("ctl.start", "bluetoothd") < 0) {
    196         ALOGE("Failed to start bluetoothd");
    197         set_bluetooth_power(0);
    198         goto out;
    199     }
    200 
    201     ret = 0;
    202 
    203 out:
    204     if (hci_sock >= 0) close(hci_sock);
    205     return ret;
    206 }
    207 
    208 int bt_disable() {
    209     ALOGV(__FUNCTION__);
    210 
    211     int ret = -1;
    212     int hci_sock = -1;
    213 
    214     ALOGI("Stopping bluetoothd deamon");
    215     if (property_set("ctl.stop", "bluetoothd") < 0) {
    216         ALOGE("Error stopping bluetoothd");
    217         goto out;
    218     }
    219     usleep(HCID_STOP_DELAY_USEC);
    220 
    221     hci_sock = create_hci_sock();
    222     if (hci_sock < 0) goto out;
    223     ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
    224 
    225     ALOGI("Stopping hciattach deamon");
    226     if (property_set("ctl.stop", "hciattach") < 0) {
    227         ALOGE("Error stopping hciattach");
    228         goto out;
    229     }
    230 
    231     if (set_bluetooth_power(0) < 0) {
    232         goto out;
    233     }
    234     ret = 0;
    235 
    236 out:
    237     if (hci_sock >= 0) close(hci_sock);
    238     return ret;
    239 }
    240 
    241 int bt_is_enabled() {
    242     ALOGV(__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     if (dev_info.flags & (1 << (HCI_UP & 31))) {
    266         ret = 1;
    267     } else {
    268         ret = 0;
    269     }
    270 
    271 out:
    272     if (hci_sock >= 0) close(hci_sock);
    273     return ret;
    274 }
    275 
    276 int ba2str(const bdaddr_t *ba, char *str) {
    277     return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
    278                 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
    279 }
    280 
    281 int str2ba(const char *str, bdaddr_t *ba) {
    282     int i;
    283     for (i = 5; i >= 0; i--) {
    284         ba->b[i] = (uint8_t) strtoul(str, (char **) &str, 16);
    285         str++;
    286     }
    287     return 0;
    288 }
    289