1 /********************************************************************** 2 * 3 * Copyright (C) 2015 Intel Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 * implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 **********************************************************************/ 19 20 #define LOG_TAG "bt_vendor" 21 22 #include <errno.h> 23 #include <stdlib.h> 24 #include <fcntl.h> 25 #include <stdint.h> 26 #include <string.h> 27 #include <poll.h> 28 29 #include <sys/socket.h> 30 #include <sys/ioctl.h> 31 32 #include "hci/include/bt_vendor_lib.h" 33 #include "osi/include/log.h" 34 #include "osi/include/properties.h" 35 36 #define BTPROTO_HCI 1 37 #define HCI_CHANNEL_USER 1 38 #define HCI_CHANNEL_CONTROL 3 39 #define HCI_DEV_NONE 0xffff 40 41 #define RFKILL_TYPE_BLUETOOTH 2 42 #define RFKILL_OP_CHANGE_ALL 3 43 44 #define MGMT_OP_INDEX_LIST 0x0003 45 #define MGMT_EV_INDEX_ADDED 0x0004 46 #define MGMT_EV_COMMAND_COMP 0x0001 47 #define MGMT_EV_SIZE_MAX 1024 48 #define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */ 49 50 #define IOCTL_HCIDEVDOWN _IOW('H', 202, int) 51 52 struct sockaddr_hci { 53 sa_family_t hci_family; 54 unsigned short hci_dev; 55 unsigned short hci_channel; 56 }; 57 58 struct rfkill_event { 59 uint32_t idx; 60 uint8_t type; 61 uint8_t op; 62 uint8_t soft, hard; 63 } __attribute__((packed)); 64 65 struct mgmt_pkt { 66 uint16_t opcode; 67 uint16_t index; 68 uint16_t len; 69 uint8_t data[MGMT_EV_SIZE_MAX]; 70 } __attribute__((packed)); 71 72 struct mgmt_event_read_index { 73 uint16_t cc_opcode; 74 uint8_t status; 75 uint16_t num_intf; 76 uint16_t index[0]; 77 } __attribute__((packed)); 78 79 static const bt_vendor_callbacks_t *bt_vendor_callbacks; 80 static unsigned char bt_vendor_local_bdaddr[6]; 81 static int bt_vendor_fd = -1; 82 static int hci_interface; 83 static int rfkill_en; 84 static int bt_hwcfg_en; 85 86 static int bt_vendor_init(const bt_vendor_callbacks_t *p_cb, 87 unsigned char *local_bdaddr) 88 { 89 char prop_value[PROPERTY_VALUE_MAX]; 90 91 LOG_INFO(LOG_TAG, "%s", __func__); 92 93 if (p_cb == NULL) { 94 LOG_ERROR(LOG_TAG, "init failed with no user callbacks!"); 95 return -1; 96 } 97 98 bt_vendor_callbacks = p_cb; 99 100 memcpy(bt_vendor_local_bdaddr, local_bdaddr, 101 sizeof(bt_vendor_local_bdaddr)); 102 103 osi_property_get("bluetooth.interface", prop_value, "0"); 104 105 errno = 0; 106 if (memcmp(prop_value, "hci", 3)) 107 hci_interface = strtol(prop_value, NULL, 10); 108 else 109 hci_interface = strtol(prop_value + 3, NULL, 10); 110 if (errno) 111 hci_interface = 0; 112 113 LOG_INFO(LOG_TAG, "Using interface hci%d", hci_interface); 114 115 osi_property_get("bluetooth.rfkill", prop_value, "0"); 116 117 rfkill_en = atoi(prop_value); 118 if (rfkill_en) 119 LOG_INFO(LOG_TAG, "RFKILL enabled"); 120 121 bt_hwcfg_en = osi_property_get("bluetooth.hwcfg", 122 prop_value, NULL) > 0 ? 1 : 0; 123 if (bt_hwcfg_en) 124 LOG_INFO(LOG_TAG, "HWCFG enabled"); 125 126 return 0; 127 } 128 129 static int bt_vendor_hw_cfg(int stop) 130 { 131 if (!bt_hwcfg_en) 132 return 0; 133 134 if (stop) { 135 if (osi_property_set("bluetooth.hwcfg", "stop") < 0) { 136 LOG_ERROR(LOG_TAG, "%s cannot stop btcfg service via prop", __func__); 137 return 1; 138 } 139 } else { 140 if (osi_property_set("bluetooth.hwcfg", "start") < 0) { 141 LOG_ERROR(LOG_TAG, "%s cannot start btcfg service via prop", __func__); 142 return 1; 143 } 144 } 145 return 0; 146 } 147 148 static int bt_vendor_wait_hcidev(void) 149 { 150 struct sockaddr_hci addr; 151 struct pollfd fds[1]; 152 struct mgmt_pkt ev; 153 int fd; 154 int ret = 0; 155 156 LOG_INFO(LOG_TAG, "%s", __func__); 157 158 fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 159 if (fd < 0) { 160 LOG_ERROR(LOG_TAG, "Bluetooth socket error: %s", strerror(errno)); 161 return -1; 162 } 163 164 memset(&addr, 0, sizeof(addr)); 165 addr.hci_family = AF_BLUETOOTH; 166 addr.hci_dev = HCI_DEV_NONE; 167 addr.hci_channel = HCI_CHANNEL_CONTROL; 168 169 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 170 LOG_ERROR(LOG_TAG, "HCI Channel Control: %s", strerror(errno)); 171 close(fd); 172 return -1; 173 } 174 175 fds[0].fd = fd; 176 fds[0].events = POLLIN; 177 178 /* Read Controller Index List Command */ 179 ev.opcode = MGMT_OP_INDEX_LIST; 180 ev.index = HCI_DEV_NONE; 181 ev.len = 0; 182 183 ssize_t wrote; 184 OSI_NO_INTR(wrote = write(fd, &ev, 6)); 185 if (wrote != 6) { 186 LOG_ERROR(LOG_TAG, "Unable to write mgmt command: %s", strerror(errno)); 187 ret = -1; 188 goto end; 189 } 190 191 while (1) { 192 int n; 193 OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT)); 194 if (n == -1) { 195 LOG_ERROR(LOG_TAG, "Poll error: %s", strerror(errno)); 196 ret = -1; 197 break; 198 } else if (n == 0) { 199 LOG_ERROR(LOG_TAG, "Timeout, no HCI device detected"); 200 ret = -1; 201 break; 202 } 203 204 if (fds[0].revents & POLLIN) { 205 OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt))); 206 if (n < 0) { 207 LOG_ERROR(LOG_TAG, "Error reading control channel: %s", 208 strerror(errno)); 209 ret = -1; 210 break; 211 } 212 213 if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) { 214 goto end; 215 } else if (ev.opcode == MGMT_EV_COMMAND_COMP) { 216 struct mgmt_event_read_index *cc; 217 int i; 218 219 cc = (struct mgmt_event_read_index *)ev.data; 220 221 if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) 222 continue; 223 224 for (i = 0; i < cc->num_intf; i++) { 225 if (cc->index[i] == hci_interface) 226 goto end; 227 } 228 } 229 } 230 } 231 232 end: 233 close(fd); 234 return ret; 235 } 236 237 static int bt_vendor_open(void *param) 238 { 239 int (*fd_array)[] = (int (*)[]) param; 240 int fd; 241 242 LOG_INFO(LOG_TAG, "%s", __func__); 243 244 fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 245 if (fd < 0) { 246 LOG_ERROR(LOG_TAG, "socket create error %s", strerror(errno)); 247 return -1; 248 } 249 250 (*fd_array)[CH_CMD] = fd; 251 (*fd_array)[CH_EVT] = fd; 252 (*fd_array)[CH_ACL_OUT] = fd; 253 (*fd_array)[CH_ACL_IN] = fd; 254 255 bt_vendor_fd = fd; 256 257 LOG_INFO(LOG_TAG, "%s returning %d", __func__, bt_vendor_fd); 258 259 return 1; 260 } 261 262 static int bt_vendor_close(void *param) 263 { 264 (void)(param); 265 266 LOG_INFO(LOG_TAG, "%s", __func__); 267 268 if (bt_vendor_fd != -1) { 269 close(bt_vendor_fd); 270 bt_vendor_fd = -1; 271 } 272 273 return 0; 274 } 275 276 static int bt_vendor_rfkill(int block) 277 { 278 struct rfkill_event event; 279 int fd; 280 281 LOG_INFO(LOG_TAG, "%s", __func__); 282 283 fd = open("/dev/rfkill", O_WRONLY); 284 if (fd < 0) { 285 LOG_ERROR(LOG_TAG, "Unable to open /dev/rfkill"); 286 return -1; 287 } 288 289 memset(&event, 0, sizeof(struct rfkill_event)); 290 event.op = RFKILL_OP_CHANGE_ALL; 291 event.type = RFKILL_TYPE_BLUETOOTH; 292 event.hard = block; 293 event.soft = block; 294 295 ssize_t len; 296 OSI_NO_INTR(len = write(fd, &event, sizeof(event))); 297 if (len < 0) { 298 LOG_ERROR(LOG_TAG, "Failed to change rfkill state"); 299 close(fd); 300 return 1; 301 } 302 303 close(fd); 304 return 0; 305 } 306 307 /* TODO: fw config should thread the device waiting and return immedialty */ 308 static void bt_vendor_fw_cfg(void) 309 { 310 struct sockaddr_hci addr; 311 int fd = bt_vendor_fd; 312 313 LOG_INFO(LOG_TAG, "%s", __func__); 314 315 if (fd == -1) { 316 LOG_ERROR(LOG_TAG, "bt_vendor_fd: %s", strerror(EBADF)); 317 goto failure; 318 } 319 320 memset(&addr, 0, sizeof(addr)); 321 addr.hci_family = AF_BLUETOOTH; 322 addr.hci_dev = hci_interface; 323 addr.hci_channel = HCI_CHANNEL_USER; 324 325 if (bt_vendor_wait_hcidev()) { 326 LOG_ERROR(LOG_TAG, "HCI interface (%d) not found", hci_interface); 327 goto failure; 328 } 329 330 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 331 LOG_ERROR(LOG_TAG, "socket bind error %s", strerror(errno)); 332 goto failure; 333 } 334 335 LOG_INFO(LOG_TAG, "HCI device ready"); 336 337 bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS); 338 339 return; 340 341 failure: 342 LOG_ERROR(LOG_TAG, "Hardware Config Error"); 343 bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL); 344 } 345 346 static int bt_vendor_op(bt_vendor_opcode_t opcode, void *param) 347 { 348 int retval = 0; 349 350 LOG_INFO(LOG_TAG, "%s op %d", __func__, opcode); 351 352 switch (opcode) { 353 case BT_VND_OP_POWER_CTRL: 354 if (!rfkill_en || !param) 355 break; 356 357 if (*((int *)param) == BT_VND_PWR_ON) { 358 retval = bt_vendor_rfkill(0); 359 if (!retval) 360 retval = bt_vendor_hw_cfg(0); 361 } else { 362 retval = bt_vendor_hw_cfg(1); 363 if (!retval) 364 retval = bt_vendor_rfkill(1); 365 } 366 367 break; 368 369 case BT_VND_OP_FW_CFG: 370 bt_vendor_fw_cfg(); 371 break; 372 373 case BT_VND_OP_SCO_CFG: 374 bt_vendor_callbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS); 375 break; 376 377 case BT_VND_OP_USERIAL_OPEN: 378 retval = bt_vendor_open(param); 379 break; 380 381 case BT_VND_OP_USERIAL_CLOSE: 382 retval = bt_vendor_close(param); 383 break; 384 385 case BT_VND_OP_GET_LPM_IDLE_TIMEOUT: 386 *((uint32_t *)param) = 3000; 387 retval = 0; 388 break; 389 390 case BT_VND_OP_LPM_SET_MODE: 391 bt_vendor_callbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS); 392 break; 393 394 case BT_VND_OP_LPM_WAKE_SET_STATE: 395 break; 396 397 case BT_VND_OP_SET_AUDIO_STATE: 398 bt_vendor_callbacks->audio_state_cb(BT_VND_OP_RESULT_SUCCESS); 399 break; 400 401 case BT_VND_OP_EPILOG: 402 bt_vendor_callbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS); 403 break; 404 } 405 406 LOG_INFO(LOG_TAG, "%s op %d retval %d", __func__, opcode, retval); 407 408 return retval; 409 } 410 411 static void bt_vendor_cleanup(void) 412 { 413 LOG_INFO(LOG_TAG, "%s", __func__); 414 415 bt_vendor_callbacks = NULL; 416 } 417 418 EXPORT_SYMBOL const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = { 419 sizeof(bt_vendor_interface_t), 420 bt_vendor_init, 421 bt_vendor_op, 422 bt_vendor_cleanup, 423 }; 424