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