Home | History | Annotate | Download | only in linux
      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