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 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
     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 #endif
    140 
    141 static inline int create_hci_sock() {
    142     int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
    143     if (sk < 0) {
    144         ALOGE("Failed to create bluetooth hci socket: %s (%d)",
    145              strerror(errno), errno);
    146     }
    147     return sk;
    148 }
    149 
    150 int bt_enable() {
    151     ALOGV(__FUNCTION__);
    152 
    153     int ret = -1;
    154     int hci_sock = -1;
    155     int attempt;
    156 
    157 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
    158     if (set_bluetooth_power(1) < 0) goto out;
    159 #endif
    160 
    161 #ifndef BLUETOOTH_HCIATTACH_USING_PROPERTY
    162     ALOGI("Starting hciattach daemon");
    163     if (property_set("ctl.start", "hciattach") < 0)
    164 #else
    165     ALOGI("Enable hci tranport");
    166     if (property_set("bluetooth.hciattach", "true") < 0)
    167 #endif
    168     {
    169         ALOGE("Failed to start hciattach");
    170 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
    171         set_bluetooth_power(0);
    172 #endif
    173         goto out;
    174     }
    175 
    176     // Try for 10 seconds, this can only succeed once hciattach has sent the
    177     // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
    178     for (attempt = 100; attempt > 0;  attempt--) {
    179         hci_sock = create_hci_sock();
    180         if (hci_sock < 0) goto out;
    181 
    182         ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID);
    183 
    184         if (!ret) {
    185             break;
    186         } else if (errno == EALREADY) {
    187             ALOGW("Bluetoothd already started, unexpectedly!");
    188             break;
    189         }
    190 
    191         ALOGI("%s: ioctl(%d, HCIDEVUP, HCI_DEV_ID) failed: %s (%d)",
    192               __FUNCTION__, hci_sock, strerror(errno), errno);
    193 
    194         close(hci_sock);
    195         usleep(100 * 1000);  // 100 ms retry delay
    196     }
    197     if (attempt == 0) {
    198         ALOGE("%s: Timeout waiting for HCI device to come up, error- %d, ",
    199             __FUNCTION__, ret);
    200         if (property_set("ctl.stop", "hciattach") < 0) {
    201             ALOGE("Error stopping hciattach");
    202         }
    203 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
    204         set_bluetooth_power(0);
    205 #endif
    206         goto out;
    207     }
    208 
    209     ALOGI("Starting bluetoothd deamon");
    210     if (property_set("ctl.start", "bluetoothd") < 0) {
    211         ALOGE("Failed to start bluetoothd");
    212 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
    213         set_bluetooth_power(0);
    214 #endif
    215         goto out;
    216     }
    217 
    218     ret = 0;
    219 
    220 out:
    221     if (hci_sock >= 0) close(hci_sock);
    222     return ret;
    223 }
    224 
    225 int bt_disable() {
    226     ALOGV(__FUNCTION__);
    227 
    228     int ret = -1;
    229     int hci_sock = -1;
    230 
    231     ALOGI("Stopping bluetoothd deamon");
    232     if (property_set("ctl.stop", "bluetoothd") < 0) {
    233         ALOGE("Error stopping bluetoothd");
    234         goto out;
    235     }
    236     usleep(HCID_STOP_DELAY_USEC);
    237 
    238     hci_sock = create_hci_sock();
    239     if (hci_sock < 0) goto out;
    240     ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
    241 
    242 #ifndef BLUETOOTH_HCIATTACH_USING_PROPERTY
    243     ALOGI("Stopping hciattach deamon");
    244     if (property_set("ctl.stop", "hciattach") < 0)
    245 #else
    246     ALOGI("Disable hci tranport");
    247     if (property_set("bluetooth.hciattach", "false") < 0)
    248 #endif
    249     {
    250         ALOGE("Error stopping hciattach");
    251         goto out;
    252     }
    253 
    254 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
    255     if (set_bluetooth_power(0) < 0) {
    256         goto out;
    257     }
    258 #endif
    259     ret = 0;
    260 
    261 out:
    262     if (hci_sock >= 0) close(hci_sock);
    263     return ret;
    264 }
    265 
    266 int bt_is_enabled() {
    267     ALOGV(__FUNCTION__);
    268 
    269     int hci_sock = -1;
    270     int ret = -1;
    271     struct hci_dev_info dev_info;
    272 
    273 
    274 #ifndef BLUETOOTH_DOES_NOT_USE_RFKILL
    275     // Check power first
    276     ret = check_bluetooth_power();
    277     if (ret == -1 || ret == 0) goto out;
    278 #endif
    279 
    280     ret = -1;
    281 
    282     // Power is on, now check if the HCI interface is up
    283     hci_sock = create_hci_sock();
    284     if (hci_sock < 0) goto out;
    285 
    286     dev_info.dev_id = HCI_DEV_ID;
    287     if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
    288         ret = 0;
    289         goto out;
    290     }
    291 
    292     if (dev_info.flags & (1 << (HCI_UP & 31))) {
    293         ret = 1;
    294     } else {
    295         ret = 0;
    296     }
    297 
    298 out:
    299     if (hci_sock >= 0) close(hci_sock);
    300     return ret;
    301 }
    302 
    303 int ba2str(const bdaddr_t *ba, char *str) {
    304     return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
    305                 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
    306 }
    307 
    308 int str2ba(const char *str, bdaddr_t *ba) {
    309     int i;
    310     for (i = 5; i >= 0; i--) {
    311         ba->b[i] = (uint8_t) strtoul(str, (char **) &str, 16);
    312         str++;
    313     }
    314     return 0;
    315 }
    316