bluetooth.c revision 9657b13bd143660e9285e9bec379eec12c866110
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_STOP_DELAY_USEC 500000 40 41#define MIN(x,y) (((x)<(y))?(x):(y)) 42 43 44static int rfkill_id = -1; 45static char *rfkill_state_path = NULL; 46 47 48static int init_rfkill() { 49 char path[64]; 50 char buf[16]; 51 int fd; 52 int sz; 53 int id; 54 for (id = 0; ; id++) { 55 snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id); 56 fd = open(path, O_RDONLY); 57 if (fd < 0) { 58 ALOGW("open(%s) failed: %s (%d)\n", path, strerror(errno), errno); 59 return -1; 60 } 61 sz = read(fd, &buf, sizeof(buf)); 62 close(fd); 63 if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) { 64 rfkill_id = id; 65 break; 66 } 67 } 68 69 asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id); 70 return 0; 71} 72 73static int check_bluetooth_power() { 74 int sz; 75 int fd = -1; 76 int ret = -1; 77 char buffer; 78 79 if (rfkill_id == -1) { 80 if (init_rfkill()) goto out; 81 } 82 83 fd = open(rfkill_state_path, O_RDONLY); 84 if (fd < 0) { 85 ALOGE("open(%s) failed: %s (%d)", rfkill_state_path, strerror(errno), 86 errno); 87 goto out; 88 } 89 sz = read(fd, &buffer, 1); 90 if (sz != 1) { 91 ALOGE("read(%s) failed: %s (%d)", rfkill_state_path, strerror(errno), 92 errno); 93 goto out; 94 } 95 96 switch (buffer) { 97 case '1': 98 ret = 1; 99 break; 100 case '0': 101 ret = 0; 102 break; 103 } 104 105out: 106 if (fd >= 0) close(fd); 107 return ret; 108} 109 110static int set_bluetooth_power(int on) { 111 int sz; 112 int fd = -1; 113 int ret = -1; 114 const char buffer = (on ? '1' : '0'); 115 116 if (rfkill_id == -1) { 117 if (init_rfkill()) goto out; 118 } 119 120 fd = open(rfkill_state_path, O_WRONLY); 121 if (fd < 0) { 122 ALOGE("open(%s) for write failed: %s (%d)", rfkill_state_path, 123 strerror(errno), errno); 124 goto out; 125 } 126 sz = write(fd, &buffer, 1); 127 if (sz < 0) { 128 ALOGE("write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno), 129 errno); 130 goto out; 131 } 132 ret = 0; 133 134out: 135 if (fd >= 0) close(fd); 136 return ret; 137} 138 139static inline int create_hci_sock() { 140 int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 141 if (sk < 0) { 142 ALOGE("Failed to create bluetooth hci socket: %s (%d)", 143 strerror(errno), errno); 144 } 145 return sk; 146} 147 148int bt_enable() { 149 ALOGV(__FUNCTION__); 150 151 int ret = -1; 152 int hci_sock = -1; 153 int attempt; 154 155 if (set_bluetooth_power(1) < 0) goto out; 156 157 ALOGI("Starting hciattach daemon"); 158 if (property_set("ctl.start", "hciattach") < 0) { 159 ALOGE("Failed to start hciattach"); 160 set_bluetooth_power(0); 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 ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID); 171 172 ALOGI("bt_enable: ret: %d, errno: %d", ret, errno); 173 if (!ret) { 174 break; 175 } else if (errno == EALREADY) { 176 ALOGW("Bluetoothd already started, unexpectedly!"); 177 break; 178 } 179 180 close(hci_sock); 181 usleep(100000); // 100 ms retry delay 182 } 183 if (attempt == 0) { 184 ALOGE("%s: Timeout waiting for HCI device to come up, error- %d, ", 185 __FUNCTION__, ret); 186 if (property_set("ctl.stop", "hciattach") < 0) { 187 ALOGE("Error stopping hciattach"); 188 } 189 set_bluetooth_power(0); 190 goto out; 191 } 192 193 ALOGI("Starting bluetoothd deamon"); 194 if (property_set("ctl.start", "bluetoothd") < 0) { 195 ALOGE("Failed to start bluetoothd"); 196 set_bluetooth_power(0); 197 goto out; 198 } 199 200 ret = 0; 201 202out: 203 if (hci_sock >= 0) close(hci_sock); 204 return ret; 205} 206 207int bt_disable() { 208 ALOGV(__FUNCTION__); 209 210 int ret = -1; 211 int hci_sock = -1; 212 213 ALOGI("Stopping bluetoothd deamon"); 214 if (property_set("ctl.stop", "bluetoothd") < 0) { 215 ALOGE("Error stopping bluetoothd"); 216 goto out; 217 } 218 usleep(HCID_STOP_DELAY_USEC); 219 220 hci_sock = create_hci_sock(); 221 if (hci_sock < 0) goto out; 222 ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID); 223 224 ALOGI("Stopping hciattach deamon"); 225 if (property_set("ctl.stop", "hciattach") < 0) { 226 ALOGE("Error stopping hciattach"); 227 goto out; 228 } 229 230 if (set_bluetooth_power(0) < 0) { 231 goto out; 232 } 233 ret = 0; 234 235out: 236 if (hci_sock >= 0) close(hci_sock); 237 return ret; 238} 239 240int bt_is_enabled() { 241 ALOGV(__FUNCTION__); 242 243 int hci_sock = -1; 244 int ret = -1; 245 struct hci_dev_info dev_info; 246 247 248 // Check power first 249 ret = check_bluetooth_power(); 250 if (ret == -1 || ret == 0) goto out; 251 252 ret = -1; 253 254 // Power is on, now check if the HCI interface is up 255 hci_sock = create_hci_sock(); 256 if (hci_sock < 0) goto out; 257 258 dev_info.dev_id = HCI_DEV_ID; 259 if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) { 260 ret = 0; 261 goto out; 262 } 263 264 if (dev_info.flags & (1 << (HCI_UP & 31))) { 265 ret = 1; 266 } else { 267 ret = 0; 268 } 269 270out: 271 if (hci_sock >= 0) close(hci_sock); 272 return ret; 273} 274 275int ba2str(const bdaddr_t *ba, char *str) { 276 return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", 277 ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]); 278} 279 280int str2ba(const char *str, bdaddr_t *ba) { 281 int i; 282 for (i = 5; i >= 0; i--) { 283 ba->b[i] = (uint8_t) strtoul(str, &str, 16); 284 str++; 285 } 286 return 0; 287} 288