1 /******************************************************************************
2 *
3 * Copyright 2009-2012 Broadcom 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 implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <base/logging.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <linux/uhid.h>
24 #include <pthread.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/poll.h>
29 #include <unistd.h>
30
31 #include "bta_api.h"
32 #include "bta_hh_api.h"
33 #include "bta_hh_co.h"
34 #include "btif_hh.h"
35 #include "btif_util.h"
36 #include "osi/include/osi.h"
37
38 const char* dev_path = "/dev/uhid";
39
40 #if (BTA_HH_LE_INCLUDED == TRUE)
41 #include "btif_config.h"
42 #define BTA_HH_NV_LOAD_MAX 16
43 static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
44 #endif
45 #define GET_RPT_RSP_OFFSET 9
46 #define THREAD_NORMAL_PRIORITY 0
47 #define BT_HH_THREAD "bt_hh_thread"
48
uhid_set_non_blocking(int fd)49 void uhid_set_non_blocking(int fd) {
50 int opts = fcntl(fd, F_GETFL);
51 if (opts < 0)
52 APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__,
53 strerror(errno));
54
55 opts |= O_NONBLOCK;
56
57 if (fcntl(fd, F_SETFL, opts) < 0)
58 APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__,
59 strerror(errno));
60 }
61
62 /*Internal function to perform UHID write and error checking*/
uhid_write(int fd,const struct uhid_event * ev)63 static int uhid_write(int fd, const struct uhid_event* ev) {
64 ssize_t ret;
65 OSI_NO_INTR(ret = write(fd, ev, sizeof(*ev)));
66
67 if (ret < 0) {
68 int rtn = -errno;
69 APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __func__, strerror(errno));
70 return rtn;
71 } else if (ret != (ssize_t)sizeof(*ev)) {
72 APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu", __func__,
73 ret, sizeof(*ev));
74 return -EFAULT;
75 }
76
77 return 0;
78 }
79
80 /* Internal function to parse the events received from UHID driver*/
uhid_read_event(btif_hh_device_t * p_dev)81 static int uhid_read_event(btif_hh_device_t* p_dev) {
82 CHECK(p_dev);
83
84 struct uhid_event ev;
85 memset(&ev, 0, sizeof(ev));
86
87 ssize_t ret;
88 OSI_NO_INTR(ret = read(p_dev->fd, &ev, sizeof(ev)));
89
90 if (ret == 0) {
91 APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __func__, strerror(errno));
92 return -EFAULT;
93 } else if (ret < 0) {
94 APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __func__,
95 strerror(errno));
96 return -errno;
97 }
98
99 switch (ev.type) {
100 case UHID_START:
101 APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
102 p_dev->ready_for_data = true;
103 break;
104 case UHID_STOP:
105 APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
106 p_dev->ready_for_data = false;
107 break;
108 case UHID_OPEN:
109 APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
110 p_dev->ready_for_data = true;
111 break;
112 case UHID_CLOSE:
113 APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
114 p_dev->ready_for_data = false;
115 break;
116 case UHID_OUTPUT:
117 if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
118 APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
119 __func__, ret, sizeof(ev.type) + sizeof(ev.u.output));
120 return -EFAULT;
121 }
122
123 APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d",
124 ev.u.output.rtype, ev.u.output.size);
125 // Send SET_REPORT with feature report if the report type in output event
126 // is FEATURE
127 if (ev.u.output.rtype == UHID_FEATURE_REPORT)
128 btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT, ev.u.output.size,
129 ev.u.output.data);
130 else if (ev.u.output.rtype == UHID_OUTPUT_REPORT)
131 btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.output.size,
132 ev.u.output.data);
133 else
134 APPL_TRACE_ERROR("%s: UHID_OUTPUT: Invalid report type = %d", __func__,
135 ev.u.output.rtype);
136 break;
137 case UHID_OUTPUT_EV:
138 if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) {
139 APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
140 __func__, ret,
141 sizeof(ev.type) + sizeof(ev.u.output_ev));
142 return -EFAULT;
143 }
144 APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
145 break;
146 case UHID_FEATURE:
147 if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.feature))) {
148 APPL_TRACE_ERROR(
149 "%s: UHID_FEATURE: Invalid size read from uhid-dev: %zd < %zu",
150 __func__, ret, sizeof(ev.type) + sizeof(ev.u.feature));
151 return -EFAULT;
152 }
153 APPL_TRACE_DEBUG("UHID_FEATURE: Report type = %d", ev.u.feature.rtype);
154 p_dev->get_rpt_snt++;
155 if (p_dev->get_rpt_id_queue) {
156 uint32_t* get_rpt_id = (uint32_t*)osi_malloc(sizeof(uint32_t));
157 *get_rpt_id = ev.u.feature.id;
158 fixed_queue_enqueue(p_dev->get_rpt_id_queue, (void*)get_rpt_id);
159 }
160 if (ev.u.feature.rtype == UHID_FEATURE_REPORT)
161 btif_hh_getreport(p_dev, BTHH_FEATURE_REPORT, ev.u.feature.rnum, 0);
162 else
163 APPL_TRACE_ERROR("%s: UHID_FEATURE: Invalid report type = %d", __func__,
164 ev.u.feature.rtype);
165 break;
166
167 default:
168 APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
169 }
170
171 return 0;
172 }
173
174 /*******************************************************************************
175 *
176 * Function create_thread
177 *
178 * Description creat a select loop
179 *
180 * Returns pthread_t
181 *
182 ******************************************************************************/
create_thread(void * (* start_routine)(void *),void * arg)183 static inline pthread_t create_thread(void* (*start_routine)(void*),
184 void* arg) {
185 APPL_TRACE_DEBUG("create_thread: entered");
186 pthread_attr_t thread_attr;
187
188 pthread_attr_init(&thread_attr);
189 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
190 pthread_t thread_id = -1;
191 if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) {
192 APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
193 return -1;
194 }
195 APPL_TRACE_DEBUG("create_thread: thread created successfully");
196 return thread_id;
197 }
198
199 /*******************************************************************************
200 *
201 * Function btif_hh_poll_event_thread
202 *
203 * Description the polling thread which polls for event from UHID driver
204 *
205 * Returns void
206 *
207 ******************************************************************************/
btif_hh_poll_event_thread(void * arg)208 static void* btif_hh_poll_event_thread(void* arg) {
209 btif_hh_device_t* p_dev = (btif_hh_device_t*)arg;
210 APPL_TRACE_DEBUG("%s: Thread created fd = %d", __func__, p_dev->fd);
211 struct pollfd pfds[1];
212
213 // This thread is created by bt_main_thread with RT priority. Lower the thread
214 // priority here since the tasks in this thread is not timing critical.
215 struct sched_param sched_params;
216 sched_params.sched_priority = THREAD_NORMAL_PRIORITY;
217 if (sched_setscheduler(gettid(), SCHED_OTHER, &sched_params)) {
218 APPL_TRACE_ERROR("%s: Failed to set thread priority to normal", __func__);
219 p_dev->hh_poll_thread_id = -1;
220 return 0;
221 }
222 pthread_setname_np(pthread_self(), BT_HH_THREAD);
223
224 pfds[0].fd = p_dev->fd;
225 pfds[0].events = POLLIN;
226
227 // Set the uhid fd as non-blocking to ensure we never block the BTU thread
228 uhid_set_non_blocking(p_dev->fd);
229
230 while (p_dev->hh_keep_polling) {
231 int ret;
232 OSI_NO_INTR(ret = poll(pfds, 1, 50));
233 if (ret < 0) {
234 APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __func__,
235 strerror(errno));
236 break;
237 }
238 if (pfds[0].revents & POLLIN) {
239 APPL_TRACE_DEBUG("%s: POLLIN", __func__);
240 ret = uhid_read_event(p_dev);
241 if (ret != 0) break;
242 }
243 }
244
245 p_dev->hh_poll_thread_id = -1;
246 return 0;
247 }
248
btif_hh_close_poll_thread(btif_hh_device_t * p_dev)249 static inline void btif_hh_close_poll_thread(btif_hh_device_t* p_dev) {
250 APPL_TRACE_DEBUG("%s", __func__);
251 p_dev->hh_keep_polling = 0;
252 if (p_dev->hh_poll_thread_id > 0)
253 pthread_join(p_dev->hh_poll_thread_id, NULL);
254
255 return;
256 }
257
bta_hh_co_destroy(int fd)258 void bta_hh_co_destroy(int fd) {
259 struct uhid_event ev;
260 memset(&ev, 0, sizeof(ev));
261 ev.type = UHID_DESTROY;
262 uhid_write(fd, &ev);
263 APPL_TRACE_DEBUG("%s: Closing fd=%d", __func__, fd);
264 close(fd);
265 }
266
bta_hh_co_write(int fd,uint8_t * rpt,uint16_t len)267 int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) {
268 APPL_TRACE_VERBOSE("%s: UHID write %d", __func__, len);
269
270 struct uhid_event ev;
271 memset(&ev, 0, sizeof(ev));
272 ev.type = UHID_INPUT;
273 ev.u.input.size = len;
274 if (len > sizeof(ev.u.input.data)) {
275 APPL_TRACE_WARNING("%s: Report size greater than allowed size", __func__);
276 return -1;
277 }
278 memcpy(ev.u.input.data, rpt, len);
279
280 return uhid_write(fd, &ev);
281 }
282
283 /*******************************************************************************
284 *
285 * Function bta_hh_co_open
286 *
287 * Description When connection is opened, this call-out function is executed
288 * by HH to do platform specific initialization.
289 *
290 * Returns void.
291 ******************************************************************************/
bta_hh_co_open(uint8_t dev_handle,uint8_t sub_class,tBTA_HH_ATTR_MASK attr_mask,uint8_t app_id)292 void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
293 tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id) {
294 uint32_t i;
295 btif_hh_device_t* p_dev = NULL;
296
297 if (dev_handle == BTA_HH_INVALID_HANDLE) {
298 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
299 dev_handle);
300 return;
301 }
302
303 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
304 p_dev = &btif_hh_cb.devices[i];
305 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
306 p_dev->dev_handle == dev_handle) {
307 // We found a device with the same handle. Must be a device reconnected.
308 APPL_TRACE_WARNING(
309 "%s: Found an existing device with the same handle dev_status=%d, "
310 "address=%s, attr_mask=0x%04x, sub_class=0x%02x, app_id=%d",
311 __func__, p_dev->dev_status, p_dev->bd_addr.ToString().c_str(),
312 p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
313
314 if (p_dev->fd < 0) {
315 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
316 if (p_dev->fd < 0) {
317 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
318 strerror(errno));
319 return;
320 } else
321 APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
322 }
323
324 p_dev->hh_keep_polling = 1;
325 p_dev->hh_poll_thread_id =
326 create_thread(btif_hh_poll_event_thread, p_dev);
327 break;
328 }
329 p_dev = NULL;
330 }
331
332 if (p_dev == NULL) {
333 // Did not find a device reconnection case. Find an empty slot now.
334 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
335 if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
336 p_dev = &btif_hh_cb.devices[i];
337 p_dev->dev_handle = dev_handle;
338 p_dev->attr_mask = attr_mask;
339 p_dev->sub_class = sub_class;
340 p_dev->app_id = app_id;
341 p_dev->local_vup = false;
342
343 btif_hh_cb.device_num++;
344 // This is a new device,open the uhid driver now.
345 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
346 if (p_dev->fd < 0) {
347 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
348 strerror(errno));
349 return;
350 } else {
351 APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
352 p_dev->hh_keep_polling = 1;
353 p_dev->hh_poll_thread_id =
354 create_thread(btif_hh_poll_event_thread, p_dev);
355 }
356
357 break;
358 }
359 }
360 }
361
362 if (p_dev == NULL) {
363 APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
364 return;
365 }
366
367 p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
368 p_dev->get_rpt_id_queue = fixed_queue_new(SIZE_MAX);
369 CHECK(p_dev->get_rpt_id_queue);
370
371 APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
372 }
373
374 /*******************************************************************************
375 *
376 * Function bta_hh_co_close
377 *
378 * Description When connection is closed, this call-out function is executed
379 * by HH to do platform specific finalization.
380 *
381 * Parameters dev_handle - device handle
382 * app_id - application id
383 *
384 * Returns void.
385 ******************************************************************************/
bta_hh_co_close(uint8_t dev_handle,uint8_t app_id)386 void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) {
387 uint32_t i;
388 btif_hh_device_t* p_dev = NULL;
389
390 APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle,
391 app_id);
392 if (dev_handle == BTA_HH_INVALID_HANDLE) {
393 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
394 dev_handle);
395 return;
396 }
397
398 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
399 p_dev = &btif_hh_cb.devices[i];
400 fixed_queue_flush(p_dev->get_rpt_id_queue, osi_free);
401 fixed_queue_free(p_dev->get_rpt_id_queue, NULL);
402 p_dev->get_rpt_id_queue = NULL;
403 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
404 p_dev->dev_handle == dev_handle) {
405 APPL_TRACE_WARNING(
406 "%s: Found an existing device with the same handle "
407 "dev_status = %d, dev_handle =%d",
408 __func__, p_dev->dev_status, p_dev->dev_handle);
409 btif_hh_close_poll_thread(p_dev);
410 break;
411 }
412 }
413 }
414
415 /*******************************************************************************
416 *
417 * Function bta_hh_co_data
418 *
419 * Description This function is executed by BTA when HID host receive a
420 * data report.
421 *
422 * Parameters dev_handle - device handle
423 * *p_rpt - pointer to the report data
424 * len - length of report data
425 * mode - Hid host Protocol Mode
426 * sub_clas - Device Subclass
427 * app_id - application id
428 *
429 * Returns void
430 ******************************************************************************/
bta_hh_co_data(uint8_t dev_handle,uint8_t * p_rpt,uint16_t len,tBTA_HH_PROTO_MODE mode,uint8_t sub_class,uint8_t ctry_code,UNUSED_ATTR const RawAddress & peer_addr,uint8_t app_id)431 void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len,
432 tBTA_HH_PROTO_MODE mode, uint8_t sub_class,
433 uint8_t ctry_code, UNUSED_ATTR const RawAddress& peer_addr,
434 uint8_t app_id) {
435 btif_hh_device_t* p_dev;
436
437 APPL_TRACE_DEBUG(
438 "%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
439 "ctry_code = %d, app_id = %d",
440 __func__, dev_handle, sub_class, mode, ctry_code, app_id);
441
442 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
443 if (p_dev == NULL) {
444 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
445 dev_handle);
446 return;
447 }
448
449 // Wait a maximum of MAX_POLLING_ATTEMPTS x POLLING_SLEEP_DURATION in case
450 // device creation is pending.
451 if (p_dev->fd >= 0) {
452 uint32_t polling_attempts = 0;
453 while (!p_dev->ready_for_data &&
454 polling_attempts++ < BTIF_HH_MAX_POLLING_ATTEMPTS) {
455 usleep(BTIF_HH_POLLING_SLEEP_DURATION_US);
456 }
457 }
458
459 // Send the HID data to the kernel.
460 if ((p_dev->fd >= 0) && p_dev->ready_for_data) {
461 bta_hh_co_write(p_dev->fd, p_rpt, len);
462 } else {
463 APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __func__,
464 p_dev->fd, p_dev->ready_for_data, len);
465 }
466 }
467
468 /*******************************************************************************
469 *
470 * Function bta_hh_co_send_hid_info
471 *
472 * Description This function is called in btif_hh.c to process DSCP
473 * received.
474 *
475 * Parameters dev_handle - device handle
476 * dscp_len - report descriptor length
477 * *p_dscp - report descriptor
478 *
479 * Returns void
480 ******************************************************************************/
bta_hh_co_send_hid_info(btif_hh_device_t * p_dev,const char * dev_name,uint16_t vendor_id,uint16_t product_id,uint16_t version,uint8_t ctry_code,int dscp_len,uint8_t * p_dscp)481 void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name,
482 uint16_t vendor_id, uint16_t product_id,
483 uint16_t version, uint8_t ctry_code, int dscp_len,
484 uint8_t* p_dscp) {
485 int result;
486 struct uhid_event ev;
487
488 if (p_dev->fd < 0) {
489 APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd,
490 dscp_len);
491 return;
492 }
493
494 APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __func__,
495 p_dev->fd, dev_name, dscp_len);
496 APPL_TRACE_WARNING(
497 "%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
498 "ctry_code=0x%02x",
499 __func__, vendor_id, product_id, version, ctry_code);
500
501 // Create and send hid descriptor to kernel
502 memset(&ev, 0, sizeof(ev));
503 ev.type = UHID_CREATE;
504 strlcpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name));
505 snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq), "%s",
506 p_dev->bd_addr.ToString().c_str());
507 ev.u.create.rd_size = dscp_len;
508 ev.u.create.rd_data = p_dscp;
509 ev.u.create.bus = BUS_BLUETOOTH;
510 ev.u.create.vendor = vendor_id;
511 ev.u.create.product = product_id;
512 ev.u.create.version = version;
513 ev.u.create.country = ctry_code;
514 result = uhid_write(p_dev->fd, &ev);
515
516 APPL_TRACE_WARNING(
517 "%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __func__,
518 p_dev->fd, dscp_len, result);
519
520 if (result) {
521 APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __func__,
522 result);
523
524 /* The HID report descriptor is corrupted. Close the driver. */
525 close(p_dev->fd);
526 p_dev->fd = -1;
527 }
528 }
529
530 /*******************************************************************************
531 *
532 * Function bta_hh_co_set_rpt_rsp
533 *
534 * Description This callout function is executed by HH when Set Report
535 * Response is received on Control Channel.
536 *
537 * Returns void.
538 *
539 ******************************************************************************/
bta_hh_co_set_rpt_rsp(uint8_t dev_handle,uint8_t status)540 void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) {
541 APPL_TRACE_ERROR("%s: Error: UHID_SET_REPORT_REPLY not supported", __func__);
542 }
543
544 /*******************************************************************************
545 *
546 * Function bta_hh_co_get_rpt_rsp
547 *
548 * Description This callout function is executed by HH when Get Report
549 * Response is received on Control Channel.
550 *
551 * Returns void.
552 *
553 ******************************************************************************/
bta_hh_co_get_rpt_rsp(uint8_t dev_handle,uint8_t status,uint8_t * p_rpt,uint16_t len)554 void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, uint8_t* p_rpt,
555 uint16_t len) {
556 struct uhid_event ev;
557 btif_hh_device_t* p_dev;
558
559 APPL_TRACE_VERBOSE("%s: dev_handle = %d", __func__, dev_handle);
560
561 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
562 if (p_dev == NULL) {
563 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
564 dev_handle);
565 return;
566 }
567
568 if (!p_dev->get_rpt_id_queue) {
569 APPL_TRACE_WARNING("%s: Error: missing UHID_GET_REPORT id queue", __func__);
570 return;
571 }
572
573 // Send the HID report to the kernel.
574 if (p_dev->fd >= 0 && p_dev->get_rpt_snt--) {
575 uint32_t* get_rpt_id =
576 (uint32_t*)fixed_queue_dequeue(p_dev->get_rpt_id_queue);
577 memset(&ev, 0, sizeof(ev));
578 ev.type = UHID_FEATURE_ANSWER;
579 ev.u.feature_answer.id = *get_rpt_id;
580 ev.u.feature_answer.err = status;
581 ev.u.feature_answer.size = len;
582 osi_free(get_rpt_id);
583 if (len > 0) {
584 if (len > UHID_DATA_MAX) {
585 APPL_TRACE_WARNING("%s: Report size greater than allowed size",
586 __func__);
587 return;
588 }
589 memcpy(ev.u.feature_answer.data, p_rpt + GET_RPT_RSP_OFFSET, len);
590 uhid_write(p_dev->fd, &ev);
591 }
592 }
593 }
594
595 #if (BTA_HH_LE_INCLUDED == TRUE)
596 /*******************************************************************************
597 *
598 * Function bta_hh_le_co_rpt_info
599 *
600 * Description This callout function is to convey the report information on
601 * a HOGP device to the application. Application can save this
602 * information in NV if device is bonded and load it back when
603 * stack reboot.
604 *
605 * Parameters remote_bda - remote device address
606 * p_entry - report entry pointer
607 * app_id - application id
608 *
609 * Returns void.
610 *
611 ******************************************************************************/
bta_hh_le_co_rpt_info(const RawAddress & remote_bda,tBTA_HH_RPT_CACHE_ENTRY * p_entry,UNUSED_ATTR uint8_t app_id)612 void bta_hh_le_co_rpt_info(const RawAddress& remote_bda,
613 tBTA_HH_RPT_CACHE_ENTRY* p_entry,
614 UNUSED_ATTR uint8_t app_id) {
615 unsigned idx = 0;
616
617 std::string addrstr = remote_bda.ToString();
618 const char* bdstr = addrstr.c_str();
619
620 size_t len = btif_config_get_bin_length(bdstr, "HidReport");
621 if (len >= sizeof(tBTA_HH_RPT_CACHE_ENTRY) && len <= sizeof(sReportCache)) {
622 btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
623 idx = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
624 }
625
626 if (idx < BTA_HH_NV_LOAD_MAX) {
627 memcpy(&sReportCache[idx++], p_entry, sizeof(tBTA_HH_RPT_CACHE_ENTRY));
628 btif_config_set_bin(bdstr, "HidReport", (const uint8_t*)sReportCache,
629 idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY));
630 BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __func__, bdstr,
631 idx);
632 }
633 }
634
635 /*******************************************************************************
636 *
637 * Function bta_hh_le_co_cache_load
638 *
639 * Description This callout function is to request the application to load
640 * the cached HOGP report if there is any. When cache reading
641 * is completed, bta_hh_le_ci_cache_load() is called by the
642 * application.
643 *
644 * Parameters remote_bda - remote device address
645 * p_num_rpt: number of cached report
646 * app_id - application id
647 *
648 * Returns the acched report array
649 *
650 ******************************************************************************/
bta_hh_le_co_cache_load(const RawAddress & remote_bda,uint8_t * p_num_rpt,UNUSED_ATTR uint8_t app_id)651 tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(const RawAddress& remote_bda,
652 uint8_t* p_num_rpt,
653 UNUSED_ATTR uint8_t app_id) {
654 std::string addrstr = remote_bda.ToString();
655 const char* bdstr = addrstr.c_str();
656
657 size_t len = btif_config_get_bin_length(bdstr, "HidReport");
658 if (!p_num_rpt || len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL;
659
660 if (len > sizeof(sReportCache)) len = sizeof(sReportCache);
661 btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
662 *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
663
664 BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt,
665 bdstr);
666
667 return sReportCache;
668 }
669
670 /*******************************************************************************
671 *
672 * Function bta_hh_le_co_reset_rpt_cache
673 *
674 * Description This callout function is to reset the HOGP device cache.
675 *
676 * Parameters remote_bda - remote device address
677 *
678 * Returns none
679 *
680 ******************************************************************************/
bta_hh_le_co_reset_rpt_cache(const RawAddress & remote_bda,UNUSED_ATTR uint8_t app_id)681 void bta_hh_le_co_reset_rpt_cache(const RawAddress& remote_bda,
682 UNUSED_ATTR uint8_t app_id) {
683 std::string addrstr = remote_bda.ToString();
684 const char* bdstr = addrstr.c_str();
685
686 btif_config_remove(bdstr, "HidReport");
687
688 BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __func__, bdstr);
689 }
690
691 #endif // (BTA_HH_LE_INCLUDED == TRUE)
692