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