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