• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
bt_vendor_init(const bt_vendor_callbacks_t * p_cb,unsigned char * local_bdaddr)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 
bt_vendor_hw_cfg(int stop)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 
bt_vendor_wait_hcidev(void)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 
bt_vendor_open(void * param)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 
bt_vendor_close(void * param)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 
bt_vendor_rfkill(int block)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 */
bt_vendor_fw_cfg(void)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 
bt_vendor_op(bt_vendor_opcode_t opcode,void * param)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 
bt_vendor_cleanup(void)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