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