system/bt
Revision | a9c30f1abb26b6d0e09a6aa2107ed3c1a94137a4 (tree) |
---|---|
Zeit | 2020-04-14 23:54:21 |
Autor | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
Add back libbt-vendor
@@ -1,3 +1,33 @@ | ||
1 | +// | |
2 | +// Copyright (C) 2019 The Android-x86 Open Source Project | |
3 | +// | |
4 | +// Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | +// you may not use this file except in compliance with the License. | |
6 | +// You may obtain a copy of the License at: | |
7 | +// | |
8 | +// http://www.apache.org/licenses/LICENSE-2.0 | |
9 | +// | |
10 | +// Unless required by applicable law or agreed to in writing, software | |
11 | +// distributed under the License is distributed on an "AS IS" BASIS, | |
12 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | +// See the License for the specific language governing permissions and | |
14 | +// limitations under the License. | |
15 | +// | |
16 | + | |
17 | +// libbt-vendor shared library for target | |
18 | +cc_library_shared { | |
19 | + name: "libbt-vendor", | |
20 | + defaults: ["fluoride_defaults"], | |
21 | + srcs: ["bt_vendor_linux.cc"], | |
22 | + include_dirs: ["system/bt"], | |
23 | + shared_libs: [ | |
24 | + "liblog", | |
25 | + "libcutils", | |
26 | + ], | |
27 | + static_libs: ["libosi"], | |
28 | + vendor: true, | |
29 | +} | |
30 | + | |
1 | 31 | subdirs = [ |
2 | 32 | "interface", |
3 | 33 | ] |
@@ -0,0 +1,411 @@ | ||
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 | + | |
55 | +struct sockaddr_hci { | |
56 | + sa_family_t hci_family; | |
57 | + unsigned short hci_dev; | |
58 | + unsigned short hci_channel; | |
59 | +}; | |
60 | + | |
61 | +struct rfkill_event { | |
62 | + uint32_t idx; | |
63 | + uint8_t type; | |
64 | + uint8_t op; | |
65 | + uint8_t soft, hard; | |
66 | +} __attribute__((packed)); | |
67 | + | |
68 | +struct 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 | + | |
75 | +struct 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 | + | |
82 | +static const bt_vendor_callbacks_t* bt_vendor_callbacks; | |
83 | +static unsigned char bt_vendor_local_bdaddr[6]; | |
84 | +static int bt_vendor_fd = -1; | |
85 | +static int hci_interface; | |
86 | +static int rfkill_en; | |
87 | +static int bt_hwcfg_en; | |
88 | + | |
89 | +static 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 | + | |
127 | +static 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 | + | |
144 | +static 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 | + | |
225 | +end: | |
226 | + close(fd); | |
227 | + return ret; | |
228 | +} | |
229 | + | |
230 | +static 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 | + | |
254 | +static 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 | + | |
267 | +static 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 */ | |
298 | +static 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 | + | |
330 | +failure: | |
331 | + LOG_ERROR(LOG_TAG, "Hardware Config Error"); | |
332 | + bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL); | |
333 | +} | |
334 | + | |
335 | +static 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 | + | |
402 | +static void bt_vendor_cleanup(void) { | |
403 | + LOG_INFO(LOG_TAG, "%s", __func__); | |
404 | + | |
405 | + bt_vendor_callbacks = NULL; | |
406 | +} | |
407 | + | |
408 | +EXPORT_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 | +}; |