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 case UHID_SET_REPORT:
167 if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.set_report))) {
168 APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
169 __func__, ret, sizeof(ev.type) + sizeof(ev.u.set_report));
170 return -EFAULT;
171 }
172
173 APPL_TRACE_DEBUG("UHID_SET_REPORT: Report type = %d, report_size = %d"
174 , ev.u.set_report.rtype, ev.u.set_report.size);
175
176 if (ev.u.set_report.rtype == UHID_FEATURE_REPORT)
177 btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
178 ev.u.set_report.size, ev.u.set_report.data);
179 else if (ev.u.set_report.rtype == UHID_OUTPUT_REPORT)
180 btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
181 ev.u.set_report.size, ev.u.set_report.data);
182 else if(ev.u.set_report.rtype == UHID_INPUT_REPORT)
183 btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
184 ev.u.set_report.size, ev.u.set_report.data);
185 else
186 APPL_TRACE_ERROR("%s:UHID_SET_REPORT: Invalid Report type = %d"
187 , __func__, ev.u.set_report.rtype);
188 break;
189 default:
190 APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
191 }
192
193 return 0;
194 }
195
196 /*******************************************************************************
197 *
198 * Function create_thread
199 *
200 * Description creat a select loop
201 *
202 * Returns pthread_t
203 *
204 ******************************************************************************/
create_thread(void * (* start_routine)(void *),void * arg)205 static inline pthread_t create_thread(void* (*start_routine)(void*),
206 void* arg) {
207 APPL_TRACE_DEBUG("create_thread: entered");
208 pthread_attr_t thread_attr;
209
210 pthread_attr_init(&thread_attr);
211 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
212 pthread_t thread_id = -1;
213 if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) {
214 APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
215 return -1;
216 }
217 APPL_TRACE_DEBUG("create_thread: thread created successfully");
218 return thread_id;
219 }
220
221 /*******************************************************************************
222 *
223 * Function btif_hh_poll_event_thread
224 *
225 * Description the polling thread which polls for event from UHID driver
226 *
227 * Returns void
228 *
229 ******************************************************************************/
btif_hh_poll_event_thread(void * arg)230 static void* btif_hh_poll_event_thread(void* arg) {
231 btif_hh_device_t* p_dev = (btif_hh_device_t*)arg;
232 APPL_TRACE_DEBUG("%s: Thread created fd = %d", __func__, p_dev->fd);
233 struct pollfd pfds[1];
234
235 // This thread is created by bt_main_thread with RT priority. Lower the thread
236 // priority here since the tasks in this thread is not timing critical.
237 struct sched_param sched_params;
238 sched_params.sched_priority = THREAD_NORMAL_PRIORITY;
239 if (sched_setscheduler(gettid(), SCHED_OTHER, &sched_params)) {
240 APPL_TRACE_ERROR("%s: Failed to set thread priority to normal", __func__);
241 p_dev->hh_poll_thread_id = -1;
242 return 0;
243 }
244 pthread_setname_np(pthread_self(), BT_HH_THREAD);
245
246 pfds[0].fd = p_dev->fd;
247 pfds[0].events = POLLIN;
248
249 // Set the uhid fd as non-blocking to ensure we never block the BTU thread
250 uhid_set_non_blocking(p_dev->fd);
251
252 while (p_dev->hh_keep_polling) {
253 int ret;
254 OSI_NO_INTR(ret = poll(pfds, 1, 50));
255 if (ret < 0) {
256 APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __func__,
257 strerror(errno));
258 break;
259 }
260 if (pfds[0].revents & POLLIN) {
261 APPL_TRACE_DEBUG("%s: POLLIN", __func__);
262 ret = uhid_read_event(p_dev);
263 if (ret != 0) break;
264 }
265 }
266
267 p_dev->hh_poll_thread_id = -1;
268 return 0;
269 }
270
btif_hh_close_poll_thread(btif_hh_device_t * p_dev)271 static inline void btif_hh_close_poll_thread(btif_hh_device_t* p_dev) {
272 APPL_TRACE_DEBUG("%s", __func__);
273 p_dev->hh_keep_polling = 0;
274 if (p_dev->hh_poll_thread_id > 0)
275 pthread_join(p_dev->hh_poll_thread_id, NULL);
276
277 return;
278 }
279
bta_hh_co_destroy(int fd)280 void bta_hh_co_destroy(int fd) {
281 struct uhid_event ev;
282 memset(&ev, 0, sizeof(ev));
283 ev.type = UHID_DESTROY;
284 uhid_write(fd, &ev);
285 APPL_TRACE_DEBUG("%s: Closing fd=%d", __func__, fd);
286 close(fd);
287 }
288
bta_hh_co_write(int fd,uint8_t * rpt,uint16_t len)289 int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) {
290 APPL_TRACE_VERBOSE("%s: UHID write %d", __func__, len);
291
292 struct uhid_event ev;
293 memset(&ev, 0, sizeof(ev));
294 ev.type = UHID_INPUT;
295 ev.u.input.size = len;
296 if (len > sizeof(ev.u.input.data)) {
297 APPL_TRACE_WARNING("%s: Report size greater than allowed size", __func__);
298 return -1;
299 }
300 memcpy(ev.u.input.data, rpt, len);
301
302 return uhid_write(fd, &ev);
303 }
304
305 /*******************************************************************************
306 *
307 * Function bta_hh_co_open
308 *
309 * Description When connection is opened, this call-out function is executed
310 * by HH to do platform specific initialization.
311 *
312 * Returns void.
313 ******************************************************************************/
bta_hh_co_open(uint8_t dev_handle,uint8_t sub_class,tBTA_HH_ATTR_MASK attr_mask,uint8_t app_id)314 void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
315 tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id) {
316 uint32_t i;
317 btif_hh_device_t* p_dev = NULL;
318
319 if (dev_handle == BTA_HH_INVALID_HANDLE) {
320 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
321 dev_handle);
322 return;
323 }
324
325 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
326 p_dev = &btif_hh_cb.devices[i];
327 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
328 p_dev->dev_handle == dev_handle) {
329 // We found a device with the same handle. Must be a device reconnected.
330 APPL_TRACE_WARNING(
331 "%s: Found an existing device with the same handle dev_status=%d, "
332 "address=%s, attr_mask=0x%04x, sub_class=0x%02x, app_id=%d",
333 __func__, p_dev->dev_status, p_dev->bd_addr.ToString().c_str(),
334 p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
335
336 if (p_dev->fd < 0) {
337 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
338 if (p_dev->fd < 0) {
339 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
340 strerror(errno));
341 return;
342 } else
343 APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
344 }
345
346 p_dev->hh_keep_polling = 1;
347 p_dev->hh_poll_thread_id =
348 create_thread(btif_hh_poll_event_thread, p_dev);
349 break;
350 }
351 p_dev = NULL;
352 }
353
354 if (p_dev == NULL) {
355 // Did not find a device reconnection case. Find an empty slot now.
356 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
357 if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
358 p_dev = &btif_hh_cb.devices[i];
359 p_dev->dev_handle = dev_handle;
360 p_dev->attr_mask = attr_mask;
361 p_dev->sub_class = sub_class;
362 p_dev->app_id = app_id;
363 p_dev->local_vup = false;
364
365 btif_hh_cb.device_num++;
366 // This is a new device,open the uhid driver now.
367 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
368 if (p_dev->fd < 0) {
369 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
370 strerror(errno));
371 return;
372 } else {
373 APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
374 p_dev->hh_keep_polling = 1;
375 p_dev->hh_poll_thread_id =
376 create_thread(btif_hh_poll_event_thread, p_dev);
377 }
378
379 break;
380 }
381 }
382 }
383
384 if (p_dev == NULL) {
385 APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
386 return;
387 }
388
389 p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
390 p_dev->get_rpt_id_queue = fixed_queue_new(SIZE_MAX);
391 CHECK(p_dev->get_rpt_id_queue);
392
393 APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
394 }
395
396 /*******************************************************************************
397 *
398 * Function bta_hh_co_close
399 *
400 * Description When connection is closed, this call-out function is executed
401 * by HH to do platform specific finalization.
402 *
403 * Parameters dev_handle - device handle
404 * app_id - application id
405 *
406 * Returns void.
407 ******************************************************************************/
bta_hh_co_close(uint8_t dev_handle,uint8_t app_id)408 void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) {
409 uint32_t i;
410 btif_hh_device_t* p_dev = NULL;
411
412 APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle,
413 app_id);
414 if (dev_handle == BTA_HH_INVALID_HANDLE) {
415 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
416 dev_handle);
417 return;
418 }
419
420 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
421 p_dev = &btif_hh_cb.devices[i];
422 fixed_queue_flush(p_dev->get_rpt_id_queue, osi_free);
423 fixed_queue_free(p_dev->get_rpt_id_queue, NULL);
424 p_dev->get_rpt_id_queue = NULL;
425 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
426 p_dev->dev_handle == dev_handle) {
427 APPL_TRACE_WARNING(
428 "%s: Found an existing device with the same handle "
429 "dev_status = %d, dev_handle =%d",
430 __func__, p_dev->dev_status, p_dev->dev_handle);
431 btif_hh_close_poll_thread(p_dev);
432 break;
433 }
434 }
435 }
436
437 /*******************************************************************************
438 *
439 * Function bta_hh_co_data
440 *
441 * Description This function is executed by BTA when HID host receive a
442 * data report.
443 *
444 * Parameters dev_handle - device handle
445 * *p_rpt - pointer to the report data
446 * len - length of report data
447 * mode - Hid host Protocol Mode
448 * sub_clas - Device Subclass
449 * app_id - application id
450 *
451 * Returns void
452 ******************************************************************************/
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)453 void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len,
454 tBTA_HH_PROTO_MODE mode, uint8_t sub_class,
455 uint8_t ctry_code, UNUSED_ATTR const RawAddress& peer_addr,
456 uint8_t app_id) {
457 btif_hh_device_t* p_dev;
458
459 APPL_TRACE_DEBUG(
460 "%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
461 "ctry_code = %d, app_id = %d",
462 __func__, dev_handle, sub_class, mode, ctry_code, app_id);
463
464 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
465 if (p_dev == NULL) {
466 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
467 dev_handle);
468 return;
469 }
470
471 // Wait a maximum of MAX_POLLING_ATTEMPTS x POLLING_SLEEP_DURATION in case
472 // device creation is pending.
473 if (p_dev->fd >= 0) {
474 uint32_t polling_attempts = 0;
475 while (!p_dev->ready_for_data &&
476 polling_attempts++ < BTIF_HH_MAX_POLLING_ATTEMPTS) {
477 usleep(BTIF_HH_POLLING_SLEEP_DURATION_US);
478 }
479 }
480
481 // Send the HID data to the kernel.
482 if ((p_dev->fd >= 0) && p_dev->ready_for_data) {
483 bta_hh_co_write(p_dev->fd, p_rpt, len);
484 } else {
485 APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __func__,
486 p_dev->fd, p_dev->ready_for_data, len);
487 }
488 }
489
490 /*******************************************************************************
491 *
492 * Function bta_hh_co_send_hid_info
493 *
494 * Description This function is called in btif_hh.c to process DSCP
495 * received.
496 *
497 * Parameters dev_handle - device handle
498 * dscp_len - report descriptor length
499 * *p_dscp - report descriptor
500 *
501 * Returns void
502 ******************************************************************************/
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)503 void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name,
504 uint16_t vendor_id, uint16_t product_id,
505 uint16_t version, uint8_t ctry_code, int dscp_len,
506 uint8_t* p_dscp) {
507 int result;
508 struct uhid_event ev;
509
510 if (p_dev->fd < 0) {
511 APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd,
512 dscp_len);
513 return;
514 }
515
516 APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __func__,
517 p_dev->fd, dev_name, dscp_len);
518 APPL_TRACE_WARNING(
519 "%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
520 "ctry_code=0x%02x",
521 __func__, vendor_id, product_id, version, ctry_code);
522
523 // Create and send hid descriptor to kernel
524 memset(&ev, 0, sizeof(ev));
525 ev.type = UHID_CREATE;
526 strlcpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name));
527 snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq), "%s",
528 p_dev->bd_addr.ToString().c_str());
529 ev.u.create.rd_size = dscp_len;
530 ev.u.create.rd_data = p_dscp;
531 ev.u.create.bus = BUS_BLUETOOTH;
532 ev.u.create.vendor = vendor_id;
533 ev.u.create.product = product_id;
534 ev.u.create.version = version;
535 ev.u.create.country = ctry_code;
536 result = uhid_write(p_dev->fd, &ev);
537
538 APPL_TRACE_WARNING(
539 "%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __func__,
540 p_dev->fd, dscp_len, result);
541
542 if (result) {
543 APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __func__,
544 result);
545
546 /* The HID report descriptor is corrupted. Close the driver. */
547 close(p_dev->fd);
548 p_dev->fd = -1;
549 }
550 }
551
552 /*******************************************************************************
553 *
554 * Function bta_hh_co_set_rpt_rsp
555 *
556 * Description This callout function is executed by HH when Set Report
557 * Response is received on Control Channel.
558 *
559 * Returns void.
560 *
561 ******************************************************************************/
bta_hh_co_set_rpt_rsp(uint8_t dev_handle,uint8_t status)562 void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) {
563 APPL_TRACE_ERROR("%s: Error: UHID_SET_REPORT_REPLY not supported", __func__);
564 }
565
566 /*******************************************************************************
567 *
568 * Function bta_hh_co_get_rpt_rsp
569 *
570 * Description This callout function is executed by HH when Get Report
571 * Response is received on Control Channel.
572 *
573 * Returns void.
574 *
575 ******************************************************************************/
bta_hh_co_get_rpt_rsp(uint8_t dev_handle,uint8_t status,uint8_t * p_rpt,uint16_t len)576 void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, uint8_t* p_rpt,
577 uint16_t len) {
578 struct uhid_event ev;
579 btif_hh_device_t* p_dev;
580
581 APPL_TRACE_VERBOSE("%s: dev_handle = %d", __func__, dev_handle);
582
583 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
584 if (p_dev == NULL) {
585 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
586 dev_handle);
587 return;
588 }
589
590 if (!p_dev->get_rpt_id_queue) {
591 APPL_TRACE_WARNING("%s: Error: missing UHID_GET_REPORT id queue", __func__);
592 return;
593 }
594
595 // Send the HID report to the kernel.
596 if (p_dev->fd >= 0 && p_dev->get_rpt_snt > 0 && p_dev->get_rpt_snt--) {
597 uint32_t* get_rpt_id =
598 (uint32_t*)fixed_queue_dequeue(p_dev->get_rpt_id_queue);
599 memset(&ev, 0, sizeof(ev));
600 ev.type = UHID_FEATURE_ANSWER;
601 ev.u.feature_answer.id = *get_rpt_id;
602 ev.u.feature_answer.err = status;
603 ev.u.feature_answer.size = len;
604 osi_free(get_rpt_id);
605 if (len > 0) {
606 if (len > UHID_DATA_MAX) {
607 APPL_TRACE_WARNING("%s: Report size greater than allowed size",
608 __func__);
609 return;
610 }
611 memcpy(ev.u.feature_answer.data, p_rpt + GET_RPT_RSP_OFFSET, len);
612 uhid_write(p_dev->fd, &ev);
613 }
614 }
615 }
616
617 #if (BTA_HH_LE_INCLUDED == TRUE)
618 /*******************************************************************************
619 *
620 * Function bta_hh_le_co_rpt_info
621 *
622 * Description This callout function is to convey the report information on
623 * a HOGP device to the application. Application can save this
624 * information in NV if device is bonded and load it back when
625 * stack reboot.
626 *
627 * Parameters remote_bda - remote device address
628 * p_entry - report entry pointer
629 * app_id - application id
630 *
631 * Returns void.
632 *
633 ******************************************************************************/
bta_hh_le_co_rpt_info(const RawAddress & remote_bda,tBTA_HH_RPT_CACHE_ENTRY * p_entry,UNUSED_ATTR uint8_t app_id)634 void bta_hh_le_co_rpt_info(const RawAddress& remote_bda,
635 tBTA_HH_RPT_CACHE_ENTRY* p_entry,
636 UNUSED_ATTR uint8_t app_id) {
637 unsigned idx = 0;
638
639 std::string addrstr = remote_bda.ToString();
640 const char* bdstr = addrstr.c_str();
641
642 size_t len = btif_config_get_bin_length(bdstr, "HidReport");
643 if (len >= sizeof(tBTA_HH_RPT_CACHE_ENTRY) && len <= sizeof(sReportCache)) {
644 btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
645 idx = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
646 }
647
648 if (idx < BTA_HH_NV_LOAD_MAX) {
649 memcpy(&sReportCache[idx++], p_entry, sizeof(tBTA_HH_RPT_CACHE_ENTRY));
650 btif_config_set_bin(bdstr, "HidReport", (const uint8_t*)sReportCache,
651 idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY));
652 BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __func__, bdstr,
653 idx);
654 }
655 }
656
657 /*******************************************************************************
658 *
659 * Function bta_hh_le_co_cache_load
660 *
661 * Description This callout function is to request the application to load
662 * the cached HOGP report if there is any. When cache reading
663 * is completed, bta_hh_le_ci_cache_load() is called by the
664 * application.
665 *
666 * Parameters remote_bda - remote device address
667 * p_num_rpt: number of cached report
668 * app_id - application id
669 *
670 * Returns the acched report array
671 *
672 ******************************************************************************/
bta_hh_le_co_cache_load(const RawAddress & remote_bda,uint8_t * p_num_rpt,UNUSED_ATTR uint8_t app_id)673 tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(const RawAddress& remote_bda,
674 uint8_t* p_num_rpt,
675 UNUSED_ATTR uint8_t app_id) {
676 std::string addrstr = remote_bda.ToString();
677 const char* bdstr = addrstr.c_str();
678
679 size_t len = btif_config_get_bin_length(bdstr, "HidReport");
680 if (!p_num_rpt || len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL;
681
682 if (len > sizeof(sReportCache)) len = sizeof(sReportCache);
683 btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
684 *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
685
686 BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt,
687 bdstr);
688
689 return sReportCache;
690 }
691
692 /*******************************************************************************
693 *
694 * Function bta_hh_le_co_reset_rpt_cache
695 *
696 * Description This callout function is to reset the HOGP device cache.
697 *
698 * Parameters remote_bda - remote device address
699 *
700 * Returns none
701 *
702 ******************************************************************************/
bta_hh_le_co_reset_rpt_cache(const RawAddress & remote_bda,UNUSED_ATTR uint8_t app_id)703 void bta_hh_le_co_reset_rpt_cache(const RawAddress& remote_bda,
704 UNUSED_ATTR uint8_t app_id) {
705 std::string addrstr = remote_bda.ToString();
706 const char* bdstr = addrstr.c_str();
707
708 btif_config_remove(bdstr, "HidReport");
709
710 BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __func__, bdstr);
711 }
712
713 #endif // (BTA_HH_LE_INCLUDED == TRUE)
714