blob: d0475eb3e341459723cad9a5a27af33d3e5950b7 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 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//#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
20
21#include <ctype.h>
22#include <fcntl.h>
The Android Open Source Project689d66b2012-12-12 17:18:15 -080023#include <sys/poll.h>
24#include <pthread.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080025#include <stdio.h>
26#include <string.h>
27#include <stdint.h>
28#include <errno.h>
29#include <linux/uhid.h>
30#include "btif_hh.h"
31#include "bta_api.h"
32#include "bta_hh_api.h"
Mike J. Chen5cd8bff2014-01-31 18:16:59 -080033#include "btif_util.h"
Chaojing Sun433fe012014-10-16 19:22:05 -070034#include "bta_hh_co.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080035
36const char *dev_path = "/dev/uhid";
37
Chaojing Sun433fe012014-10-16 19:22:05 -070038#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
39#include "btif_config.h"
40#define BTA_HH_NV_LOAD_MAX 16
41static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
42#endif
The Android Open Source Project5738f832012-12-12 16:00:35 -080043
Hemant Gupta65f2ae92014-12-16 16:47:54 +053044
45#define REPORT_DESC_REPORT_ID 0x05
46#define REPORT_DESC_DIGITIZER_PAGE 0x0D
47#define REPORT_DESC_START_COLLECTION 0xA1
48#define REPORT_DESC_END_COLLECTION 0xC0
49
50/*********************************************************
51** Local type definitions
52*********************************************************/
53
54typedef struct hid_kb_bllist
55{
56 UINT16 product_id;
57 UINT16 version_id;
58 char* kb_name;
59} tHID_KB_BLLIST;
60
61
62static tHID_KB_BLLIST hid_multitouch_bl[] =
63{
64 {0x22b8, 0x093d, "Motorola Keyboard KZ500 v122"}
65};
66
67static bool check_if_dig_desc_to_be_removed(UINT16 product_id,
68 UINT16 version_id, char* kb_name)
69{
70 int len, i;
71 len= sizeof(hid_multitouch_bl) / sizeof(tHID_KB_BLLIST);
72 for(i = 0; i< len; i++)
73 {
74 if ((hid_multitouch_bl[i].product_id == product_id) &&
75 (hid_multitouch_bl[i].version_id == version_id) &&
76 !strncmp(hid_multitouch_bl[i].kb_name, kb_name,
77 strlen(hid_multitouch_bl[i].kb_name))) {
78 BTIF_TRACE_DEBUG("%s: %s is in multitouch blacklist",
79 __FUNCTION__, kb_name);
80 return TRUE;
81 }
82 }
83 BTIF_TRACE_DEBUG("%s: %s is not in multitouch blacklist",
84 __FUNCTION__, kb_name);
85 return FALSE;
86}
87
88static void remove_digitizer_descriptor(UINT8 **data, UINT16 *length)
89{
90 UINT8 *startDescPtr = *data;
91 UINT8 *desc = *data;
92
93 /* Parse until complete report descriptor is parsed */
94 while (startDescPtr < *data + *length)
95 {
96 UINT8 item = *startDescPtr++;
97 UINT8 usage_page;
98
99 switch (item) {
100 case REPORT_DESC_REPORT_ID: // Report ID
101 usage_page = *startDescPtr;
102 if (usage_page == REPORT_DESC_DIGITIZER_PAGE)
103 {
104 // digitizer usage page
105 UINT8 *traversePtr = startDescPtr;
106 UINT8 num_of_collections = 0;
107 UINT8 num_of_end_collections = 0;
108 UINT16 remainingBytesToBeCopied = 0;
109 /* increment pointer until digitizer descriptor is parsed
110 * completely or start collection matches end collection */
111 while ((num_of_collections == 0 || (num_of_collections !=
112 num_of_end_collections)) && (traversePtr <
113 *data + *length))
114 {
115 if (*traversePtr == REPORT_DESC_START_COLLECTION) {
116 /* Increment number of collections for
117 * digitizer descriptor */
118 num_of_collections++;
119 }
120 if (*traversePtr == REPORT_DESC_END_COLLECTION) {
121 /* Increment number of end collections for
122 * digitizer descriptor */
123 num_of_end_collections++;
124 }
125 /* increment the pointer to continue parsing
126 * the digitizer descriptor */
127 *traversePtr++;
128 }
129 remainingBytesToBeCopied = *length - (traversePtr - *data);
130 BTIF_TRACE_DEBUG("starting point of digitizer desc = %d\n",
131 (startDescPtr - *data) - 1);
132 BTIF_TRACE_DEBUG("start collection = %d, end collection = "
133 " %d\n", num_of_collections, num_of_end_collections);
134 BTIF_TRACE_DEBUG("end point of digitizer desc = %d\n",
135 (traversePtr - *data));
136 BTIF_TRACE_DEBUG("length of digitizer desc = %d\n",
137 traversePtr - startDescPtr + 2);
138 BTIF_TRACE_DEBUG("bytes remaining to be copied = %d\n",
139 remainingBytesToBeCopied);
140 if (remainingBytesToBeCopied)
141 {
142 UINT32 i;
143 UINT8 *newDescPtr = traversePtr;
144 UINT32 digDescStartPoint = (startDescPtr - *data) - 1;
145 UINT32 digDescEndPoint = *length -
146 (traversePtr - startDescPtr) - 1;
147 /* copy the remaining bytes in descriptor to the
148 * existing place of digitizer descriptor */
149 for (i = digDescStartPoint; i < digDescEndPoint; i ++) {
150 desc[i] = *newDescPtr++;
151 }
152 }
153 /* update the length as digitizer descriptor is removed */
154 *length = *length - (traversePtr - startDescPtr) - 1;
155 BTIF_TRACE_DEBUG("new length of report desc = %d\n",
156 *length);
157 /* Update the start descriptor again to continue parsing
158 * for digitizer records assuming more than 1 digitizer
159 * record exists in report descriptor */
160 startDescPtr --;
161 }
162 break;
163
164 default:
165 startDescPtr += (item & 0x03);
166 break;
167 }
168 }
169}
170
The Android Open Source Project5738f832012-12-12 16:00:35 -0800171/*Internal function to perform UHID write and error checking*/
172static int uhid_write(int fd, const struct uhid_event *ev)
173{
174 ssize_t ret;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700175 ret = TEMP_FAILURE_RETRY(write(fd, ev, sizeof(*ev)));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800176 if (ret < 0){
177 int rtn = -errno;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700178 APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __FUNCTION__, strerror(errno));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800179 return rtn;
180 } else if (ret != sizeof(*ev)) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700181 APPL_TRACE_ERROR("%s: Wrong size written to uhid: %ld != %lu",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800182 __FUNCTION__, ret, sizeof(*ev));
183 return -EFAULT;
184 } else {
185 return 0;
186 }
187}
188
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800189/* Internal function to parse the events received from UHID driver*/
190static int uhid_event(btif_hh_device_t *p_dev)
191{
192 struct uhid_event ev;
193 ssize_t ret;
194 memset(&ev, 0, sizeof(ev));
195 if(!p_dev)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800196 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700197 APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800198 return -1;
199 }
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700200 ret = TEMP_FAILURE_RETRY(read(p_dev->fd, &ev, sizeof(ev)));
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800201 if (ret == 0) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700202 APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800203 strerror(errno));
204 return -EFAULT;
205 } else if (ret < 0) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700206 APPL_TRACE_ERROR("%s:Cannot read uhid-cdev: %s", __FUNCTION__,
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800207 strerror(errno));
208 return -errno;
209 } else if (ret != sizeof(ev)) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700210 APPL_TRACE_ERROR("%s:Invalid size read from uhid-dev: %ld != %lu",
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800211 __FUNCTION__, ret, sizeof(ev));
212 return -EFAULT;
213 }
214
215 switch (ev.type) {
216 case UHID_START:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700217 APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800218 break;
219 case UHID_STOP:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700220 APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800221 break;
222 case UHID_OPEN:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700223 APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800224 break;
225 case UHID_CLOSE:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700226 APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800227 break;
228 case UHID_OUTPUT:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700229 APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d"
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800230 ,ev.u.output.rtype, ev.u.output.size);
231 //Send SET_REPORT with feature report if the report type in output event is FEATURE
232 if(ev.u.output.rtype == UHID_FEATURE_REPORT)
233 btif_hh_setreport(p_dev,BTHH_FEATURE_REPORT,ev.u.output.size,ev.u.output.data);
234 else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
235 btif_hh_setreport(p_dev,BTHH_OUTPUT_REPORT,ev.u.output.size,ev.u.output.data);
236 else
237 btif_hh_setreport(p_dev,BTHH_INPUT_REPORT,ev.u.output.size,ev.u.output.data);
238 break;
239 case UHID_OUTPUT_EV:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700240 APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800241 break;
242 case UHID_FEATURE:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700243 APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800244 break;
245 case UHID_FEATURE_ANSWER:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700246 APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800247 break;
248
249 default:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700250 APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800251 }
252
253 return 0;
254}
255
256/*******************************************************************************
257**
258** Function create_thread
259**
260** Description creat a select loop
261**
262** Returns pthread_t
263**
264*******************************************************************************/
265static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg){
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700266 APPL_TRACE_DEBUG("create_thread: entered");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800267 pthread_attr_t thread_attr;
268
269 pthread_attr_init(&thread_attr);
270 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
271 pthread_t thread_id = -1;
272 if ( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
273 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700274 APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800275 return -1;
276 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700277 APPL_TRACE_DEBUG("create_thread: thread created successfully");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800278 return thread_id;
279}
280
281/*******************************************************************************
282**
283** Function btif_hh_poll_event_thread
284**
285** Description the polling thread which polls for event from UHID driver
286**
287** Returns void
288**
289*******************************************************************************/
290static void *btif_hh_poll_event_thread(void *arg)
291{
292
293 btif_hh_device_t *p_dev = arg;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700294 APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800295 struct pollfd pfds[1];
296 int ret;
297 pfds[0].fd = p_dev->fd;
298 pfds[0].events = POLLIN;
299
300 while(p_dev->hh_keep_polling){
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700301 ret = TEMP_FAILURE_RETRY(poll(pfds, 1, 50));
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800302 if (ret < 0) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700303 APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800304 break;
305 }
306 if (pfds[0].revents & POLLIN) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700307 APPL_TRACE_DEBUG("btif_hh_poll_event_thread: POLLIN");
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800308 ret = uhid_event(p_dev);
309 if (ret){
310 break;
311 }
312 }
313 }
314
315 p_dev->hh_poll_thread_id = -1;
316 return 0;
317}
318
319static inline void btif_hh_close_poll_thread(btif_hh_device_t *p_dev)
320{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700321 APPL_TRACE_DEBUG("%s", __FUNCTION__);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800322 p_dev->hh_keep_polling = 0;
323 if(p_dev->hh_poll_thread_id > 0)
324 pthread_join(p_dev->hh_poll_thread_id,NULL);
325
326 return;
327}
328
The Android Open Source Project5738f832012-12-12 16:00:35 -0800329void bta_hh_co_destroy(int fd)
330{
331 struct uhid_event ev;
332 memset(&ev, 0, sizeof(ev));
333 ev.type = UHID_DESTROY;
334 uhid_write(fd, &ev);
Hemant Gupta5021fec2014-11-19 19:09:54 +0530335 APPL_TRACE_DEBUG("%s:closing fd = %d",__FUNCTION__, fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800336 close(fd);
337}
338
339int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
340{
Hemant Gupta4c2cf792014-08-06 14:26:34 +0530341 APPL_TRACE_VERBOSE("bta_hh_co_data: UHID write");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800342 struct uhid_event ev;
343 memset(&ev, 0, sizeof(ev));
344 ev.type = UHID_INPUT;
345 ev.u.input.size = len;
346 if(len > sizeof(ev.u.input.data)){
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700347 APPL_TRACE_WARNING("%s:report size greater than allowed size",__FUNCTION__);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800348 return -1;
349 }
350 memcpy(ev.u.input.data, rpt, len);
351 return uhid_write(fd, &ev);
352
353}
354
355
356/*******************************************************************************
357**
358** Function bta_hh_co_open
359**
360** Description When connection is opened, this call-out function is executed
361** by HH to do platform specific initialization.
362**
363** Returns void.
364*******************************************************************************/
365void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
366 UINT8 app_id)
367{
368 UINT32 i;
369 btif_hh_device_t *p_dev = NULL;
370
371 if (dev_handle == BTA_HH_INVALID_HANDLE) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700372 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800373 return;
374 }
375
376 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
377 p_dev = &btif_hh_cb.devices[i];
378 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
379 // We found a device with the same handle. Must be a device reconnected.
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700380 APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
The Android Open Source Project5738f832012-12-12 16:00:35 -0800381 "dev_status = %d",__FUNCTION__,
382 p_dev->dev_status);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700383 APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800384 p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
385 p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700386 APPL_TRACE_WARNING("%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800387 __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
388
389 if(p_dev->fd<0) {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700390 p_dev->fd = TEMP_FAILURE_RETRY(open(dev_path, O_RDWR | O_CLOEXEC));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800391 if (p_dev->fd < 0){
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700392 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800393 __FUNCTION__,strerror(errno));
394 }else
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700395 APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800396 }
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800397 p_dev->hh_keep_polling = 1;
398 p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800399 break;
400 }
401 p_dev = NULL;
402 }
403
404 if (p_dev == NULL) {
405 // Did not find a device reconnection case. Find an empty slot now.
406 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
407 if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
408 p_dev = &btif_hh_cb.devices[i];
409 p_dev->dev_handle = dev_handle;
410 p_dev->attr_mask = attr_mask;
411 p_dev->sub_class = sub_class;
412 p_dev->app_id = app_id;
Ganesh Ganapathi Batta390c94d2013-05-15 17:58:35 -0700413 p_dev->local_vup = FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800414
415 btif_hh_cb.device_num++;
416 // This is a new device,open the uhid driver now.
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700417 p_dev->fd = TEMP_FAILURE_RETRY(open(dev_path, O_RDWR | O_CLOEXEC));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800418 if (p_dev->fd < 0){
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700419 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800420 __FUNCTION__,strerror(errno));
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800421 }else{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700422 APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800423 p_dev->hh_keep_polling = 1;
424 p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
425 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800426
427
428 break;
429 }
430 }
431 }
432
433 if (p_dev == NULL) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700434 APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __FUNCTION__);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800435 return;
436 }
437
438 p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700439 APPL_TRACE_DEBUG("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800440}
441
442
443/*******************************************************************************
444**
445** Function bta_hh_co_close
446**
447** Description When connection is closed, this call-out function is executed
448** by HH to do platform specific finalization.
449**
450** Parameters dev_handle - device handle
451** app_id - application id
452**
453** Returns void.
454*******************************************************************************/
455void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id)
456{
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800457 UINT32 i;
458 btif_hh_device_t *p_dev = NULL;
459
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700460 APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __FUNCTION__, dev_handle, app_id);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800461 if (dev_handle == BTA_HH_INVALID_HANDLE) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700462 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800463 return;
464 }
465
466 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
467 p_dev = &btif_hh_cb.devices[i];
468 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700469 APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800470 "dev_status = %d, dev_handle =%d"
471 ,__FUNCTION__,p_dev->dev_status
472 ,p_dev->dev_handle);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800473 btif_hh_close_poll_thread(p_dev);
474 break;
475 }
476 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800477}
478
479
480/*******************************************************************************
481**
482** Function bta_hh_co_data
483**
484** Description This function is executed by BTA when HID host receive a data
485** report.
486**
487** Parameters dev_handle - device handle
488** *p_rpt - pointer to the report data
489** len - length of report data
490** mode - Hid host Protocol Mode
491** sub_clas - Device Subclass
492** app_id - application id
493**
494** Returns void
495*******************************************************************************/
496void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode,
497 UINT8 sub_class, UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id)
498{
499 btif_hh_device_t *p_dev;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800500 UNUSED(peer_addr);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800501
Hemant Gupta4c2cf792014-08-06 14:26:34 +0530502 APPL_TRACE_VERBOSE("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
The Android Open Source Project5738f832012-12-12 16:00:35 -0800503 "ctry_code = %d, app_id = %d",
504 __FUNCTION__, dev_handle, sub_class, mode, ctry_code, app_id);
505
506 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
507 if (p_dev == NULL) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700508 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800509 return;
510 }
511 // Send the HID report to the kernel.
512 if (p_dev->fd >= 0) {
513 bta_hh_co_write(p_dev->fd, p_rpt, len);
514 }else {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700515 APPL_TRACE_WARNING("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800516 }
517}
518
519
520/*******************************************************************************
521**
522** Function bta_hh_co_send_hid_info
523**
524** Description This function is called in btif_hh.c to process DSCP received.
525**
526** Parameters dev_handle - device handle
527** dscp_len - report descriptor length
528** *p_dscp - report descriptor
529**
530** Returns void
531*******************************************************************************/
532void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id,
533 UINT16 product_id, UINT16 version, UINT8 ctry_code,
534 int dscp_len, UINT8 *p_dscp)
535{
536 int result;
537 struct uhid_event ev;
538
539 if (p_dev->fd < 0) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700540 APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __FUNCTION__, p_dev->fd, dscp_len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800541 return;
542 }
543
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700544 APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __FUNCTION__,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800545 p_dev->fd, dev_name, dscp_len);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700546 APPL_TRACE_WARNING("%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
The Android Open Source Project5738f832012-12-12 16:00:35 -0800547 "ctry_code=0x%02x",__FUNCTION__,
548 vendor_id, product_id,
549 version, ctry_code);
550
Hemant Gupta65f2ae92014-12-16 16:47:54 +0530551 if (check_if_dig_desc_to_be_removed(vendor_id, product_id, dev_name))
552 remove_digitizer_descriptor(&p_dscp, (UINT16 *)&dscp_len);
553
The Android Open Source Project5738f832012-12-12 16:00:35 -0800554//Create and send hid descriptor to kernel
555 memset(&ev, 0, sizeof(ev));
556 ev.type = UHID_CREATE;
557 strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
Zhihai Xue4c9b752013-12-11 11:46:36 -0800558 snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq),
559 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
560 p_dev->bd_addr.address[5], p_dev->bd_addr.address[4],
561 p_dev->bd_addr.address[3], p_dev->bd_addr.address[2],
562 p_dev->bd_addr.address[1], p_dev->bd_addr.address[0]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800563 ev.u.create.rd_size = dscp_len;
564 ev.u.create.rd_data = p_dscp;
565 ev.u.create.bus = BUS_BLUETOOTH;
566 ev.u.create.vendor = vendor_id;
567 ev.u.create.product = product_id;
568 ev.u.create.version = version;
569 ev.u.create.country = ctry_code;
570 result = uhid_write(p_dev->fd, &ev);
571
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700572 APPL_TRACE_WARNING("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800573 p_dev->fd, dscp_len, result);
574
575 if (result) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700576 APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __FUNCTION__, result);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800577
578 /* The HID report descriptor is corrupted. Close the driver. */
579 close(p_dev->fd);
580 p_dev->fd = -1;
581 }
582}
583
Chaojing Sun433fe012014-10-16 19:22:05 -0700584#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
585/*******************************************************************************
586**
587** Function bta_hh_le_co_rpt_info
588**
589** Description This callout function is to convey the report information on
590** a HOGP device to the application. Application can save this
591** information in NV if device is bonded and load it back when
592** stack reboot.
593**
594** Parameters remote_bda - remote device address
595** p_entry - report entry pointer
596** app_id - application id
597**
598** Returns void.
599**
600*******************************************************************************/
601void bta_hh_le_co_rpt_info(BD_ADDR remote_bda, tBTA_HH_RPT_CACHE_ENTRY *p_entry, UINT8 app_id)
602{
603 UNUSED(app_id);
604
605 unsigned len = 0;
606 unsigned type = 0;
607 unsigned idx = 0;
608
609 bdstr_t bdstr;
610 sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
611 remote_bda[0], remote_bda[1], remote_bda[2],
612 remote_bda[3], remote_bda[4], remote_bda[5]);
613
614 btif_config_get("Remote", bdstr, "HidReport", NULL, (int*)&len, (int*)&type);
615 if (len >= sizeof(tBTA_HH_RPT_CACHE_ENTRY) && len <= sizeof(sReportCache))
616 {
617 btif_config_get("Remote", bdstr, "HidReport", (char*)sReportCache, (int*)&len, (int*)&type);
618 idx = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
619 }
620
621 if (idx < BTA_HH_NV_LOAD_MAX)
622 {
623 memcpy(&sReportCache[idx++], p_entry, sizeof(tBTA_HH_RPT_CACHE_ENTRY));
624 btif_config_set("Remote", bdstr, "HidReport", (const char*)sReportCache,
625 idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY), BTIF_CFG_TYPE_BIN);
626 BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __FUNCTION__, bdstr, idx);
627 }
628}
629
630
631/*******************************************************************************
632**
633** Function bta_hh_le_co_cache_load
634**
635** Description This callout function is to request the application to load the
636** cached HOGP report if there is any. When cache reading is completed,
637** bta_hh_le_ci_cache_load() is called by the application.
638**
639** Parameters remote_bda - remote device address
640** p_num_rpt: number of cached report
641** app_id - application id
642**
643** Returns the acched report array
644**
645*******************************************************************************/
646tBTA_HH_RPT_CACHE_ENTRY * bta_hh_le_co_cache_load (BD_ADDR remote_bda,
647 UINT8 *p_num_rpt, UINT8 app_id)
648{
649 UNUSED(app_id);
650
651 unsigned len = 0;
652 unsigned type = 0;
653 unsigned idx = 0;
654
655 bdstr_t bdstr;
656 sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
657 remote_bda[0], remote_bda[1], remote_bda[2],
658 remote_bda[3], remote_bda[4], remote_bda[5]);
659
660 btif_config_get("Remote", bdstr, "HidReport", NULL, (int*)&len, (int*)&type);
661 if (!p_num_rpt && len < sizeof(tBTA_HH_RPT_CACHE_ENTRY))
662 return NULL;
663
664 if (len > sizeof(sReportCache))
665 len = sizeof(sReportCache);
666 btif_config_get("Remote", bdstr, "HidReport", (char*)sReportCache, (int*)&len, (int*)&type);
667 *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
668
669 BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __FUNCTION__, *p_num_rpt, bdstr);
670
671 return sReportCache;
672}
673
674/*******************************************************************************
675**
676** Function bta_hh_le_co_reset_rpt_cache
677**
678** Description This callout function is to reset the HOGP device cache.
679**
680** Parameters remote_bda - remote device address
681**
682** Returns none
683**
684*******************************************************************************/
685void bta_hh_le_co_reset_rpt_cache (BD_ADDR remote_bda, UINT8 app_id)
686{
687 UNUSED(app_id);
688
689 bdstr_t bdstr;
690 sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
691 remote_bda[0], remote_bda[1], remote_bda[2],
692 remote_bda[3], remote_bda[4], remote_bda[5]);
693 btif_config_remove("Remote", bdstr, "HidReport");
694
695 BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __FUNCTION__, bdstr);
696}
697#endif /* #if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE) */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800698