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