1 /******************************************************************************
3 * Copyright (C) 2009-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 //#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
29 #include <linux/uhid.h>
32 #include "bta_hh_api.h"
33 #include "btif_util.h"
36 const char *dev_path = "/dev/uhid";
39 /*Internal function to perform UHID write and error checking*/
40 static int uhid_write(int fd, const struct uhid_event *ev)
43 ret = write(fd, ev, sizeof(*ev));
46 APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __FUNCTION__, strerror(errno));
48 } else if (ret != sizeof(*ev)) {
49 APPL_TRACE_ERROR("%s: Wrong size written to uhid: %ld != %lu",
50 __FUNCTION__, ret, sizeof(*ev));
57 /* Internal function to parse the events received from UHID driver*/
58 static int uhid_event(btif_hh_device_t *p_dev)
62 memset(&ev, 0, sizeof(ev));
65 APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__)
68 ret = read(p_dev->fd, &ev, sizeof(ev));
70 APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
74 APPL_TRACE_ERROR("%s:Cannot read uhid-cdev: %s", __FUNCTION__,
77 } else if (ret != sizeof(ev)) {
78 APPL_TRACE_ERROR("%s:Invalid size read from uhid-dev: %ld != %lu",
79 __FUNCTION__, ret, sizeof(ev));
85 APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
88 APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
91 APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
94 APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
97 APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d"
98 ,ev.u.output.rtype, ev.u.output.size);
99 //Send SET_REPORT with feature report if the report type in output event is FEATURE
100 if(ev.u.output.rtype == UHID_FEATURE_REPORT)
101 btif_hh_setreport(p_dev,BTHH_FEATURE_REPORT,ev.u.output.size,ev.u.output.data);
102 else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
103 btif_hh_setreport(p_dev,BTHH_OUTPUT_REPORT,ev.u.output.size,ev.u.output.data);
105 btif_hh_setreport(p_dev,BTHH_INPUT_REPORT,ev.u.output.size,ev.u.output.data);
108 APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
111 APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
113 case UHID_FEATURE_ANSWER:
114 APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
118 APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
124 /*******************************************************************************
126 ** Function create_thread
128 ** Description creat a select loop
132 *******************************************************************************/
133 static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg){
134 APPL_TRACE_DEBUG("create_thread: entered");
135 pthread_attr_t thread_attr;
137 pthread_attr_init(&thread_attr);
138 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
139 pthread_t thread_id = -1;
140 if ( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
142 APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
145 APPL_TRACE_DEBUG("create_thread: thread created successfully");
149 /*******************************************************************************
151 ** Function btif_hh_poll_event_thread
153 ** Description the polling thread which polls for event from UHID driver
157 *******************************************************************************/
158 static void *btif_hh_poll_event_thread(void *arg)
161 btif_hh_device_t *p_dev = arg;
162 APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
163 struct pollfd pfds[1];
165 pfds[0].fd = p_dev->fd;
166 pfds[0].events = POLLIN;
168 while(p_dev->hh_keep_polling){
169 ret = poll(pfds, 1, 50);
171 APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
174 if (pfds[0].revents & POLLIN) {
175 APPL_TRACE_DEBUG("btif_hh_poll_event_thread: POLLIN");
176 ret = uhid_event(p_dev);
183 p_dev->hh_poll_thread_id = -1;
187 static inline void btif_hh_close_poll_thread(btif_hh_device_t *p_dev)
189 APPL_TRACE_DEBUG("%s", __FUNCTION__);
190 p_dev->hh_keep_polling = 0;
191 if(p_dev->hh_poll_thread_id > 0)
192 pthread_join(p_dev->hh_poll_thread_id,NULL);
197 void bta_hh_co_destroy(int fd)
199 struct uhid_event ev;
200 memset(&ev, 0, sizeof(ev));
201 ev.type = UHID_DESTROY;
206 int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
208 APPL_TRACE_DEBUG("bta_hh_co_data: UHID write");
209 struct uhid_event ev;
210 memset(&ev, 0, sizeof(ev));
211 ev.type = UHID_INPUT;
212 ev.u.input.size = len;
213 if(len > sizeof(ev.u.input.data)){
214 APPL_TRACE_WARNING("%s:report size greater than allowed size",__FUNCTION__);
217 memcpy(ev.u.input.data, rpt, len);
218 return uhid_write(fd, &ev);
223 /*******************************************************************************
225 ** Function bta_hh_co_open
227 ** Description When connection is opened, this call-out function is executed
228 ** by HH to do platform specific initialization.
231 *******************************************************************************/
232 void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
236 btif_hh_device_t *p_dev = NULL;
238 if (dev_handle == BTA_HH_INVALID_HANDLE) {
239 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
243 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
244 p_dev = &btif_hh_cb.devices[i];
245 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
246 // We found a device with the same handle. Must be a device reconnected.
247 APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
248 "dev_status = %d",__FUNCTION__,
250 APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
251 p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
252 p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
253 APPL_TRACE_WARNING("%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
254 __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
257 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
259 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
260 __FUNCTION__,strerror(errno));
262 APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
264 p_dev->hh_keep_polling = 1;
265 p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
272 // Did not find a device reconnection case. Find an empty slot now.
273 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
274 if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
275 p_dev = &btif_hh_cb.devices[i];
276 p_dev->dev_handle = dev_handle;
277 p_dev->attr_mask = attr_mask;
278 p_dev->sub_class = sub_class;
279 p_dev->app_id = app_id;
280 p_dev->local_vup = FALSE;
282 btif_hh_cb.device_num++;
283 // This is a new device,open the uhid driver now.
284 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
286 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
287 __FUNCTION__,strerror(errno));
289 APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
290 p_dev->hh_keep_polling = 1;
291 p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
301 APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __FUNCTION__);
305 p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
306 APPL_TRACE_DEBUG("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
310 /*******************************************************************************
312 ** Function bta_hh_co_close
314 ** Description When connection is closed, this call-out function is executed
315 ** by HH to do platform specific finalization.
317 ** Parameters dev_handle - device handle
318 ** app_id - application id
321 *******************************************************************************/
322 void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id)
325 btif_hh_device_t *p_dev = NULL;
327 APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __FUNCTION__, dev_handle, app_id);
328 if (dev_handle == BTA_HH_INVALID_HANDLE) {
329 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
333 for (i = 0; i < BTIF_HH_MAX_HID; i++) {
334 p_dev = &btif_hh_cb.devices[i];
335 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
336 APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
337 "dev_status = %d, dev_handle =%d"
338 ,__FUNCTION__,p_dev->dev_status
340 btif_hh_close_poll_thread(p_dev);
348 /*******************************************************************************
350 ** Function bta_hh_co_data
352 ** Description This function is executed by BTA when HID host receive a data
355 ** Parameters dev_handle - device handle
356 ** *p_rpt - pointer to the report data
357 ** len - length of report data
358 ** mode - Hid host Protocol Mode
359 ** sub_clas - Device Subclass
360 ** app_id - application id
363 *******************************************************************************/
364 void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode,
365 UINT8 sub_class, UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id)
367 btif_hh_device_t *p_dev;
370 APPL_TRACE_DEBUG("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
371 "ctry_code = %d, app_id = %d",
372 __FUNCTION__, dev_handle, sub_class, mode, ctry_code, app_id);
374 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
376 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle);
379 // Send the HID report to the kernel.
380 if (p_dev->fd >= 0) {
381 bta_hh_co_write(p_dev->fd, p_rpt, len);
383 APPL_TRACE_WARNING("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len);
388 /*******************************************************************************
390 ** Function bta_hh_co_send_hid_info
392 ** Description This function is called in btif_hh.c to process DSCP received.
394 ** Parameters dev_handle - device handle
395 ** dscp_len - report descriptor length
396 ** *p_dscp - report descriptor
399 *******************************************************************************/
400 void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id,
401 UINT16 product_id, UINT16 version, UINT8 ctry_code,
402 int dscp_len, UINT8 *p_dscp)
405 struct uhid_event ev;
408 APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __FUNCTION__, p_dev->fd, dscp_len);
412 APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __FUNCTION__,
413 p_dev->fd, dev_name, dscp_len);
414 APPL_TRACE_WARNING("%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
415 "ctry_code=0x%02x",__FUNCTION__,
416 vendor_id, product_id,
419 //Create and send hid descriptor to kernel
420 memset(&ev, 0, sizeof(ev));
421 ev.type = UHID_CREATE;
422 strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
423 snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq),
424 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
425 p_dev->bd_addr.address[5], p_dev->bd_addr.address[4],
426 p_dev->bd_addr.address[3], p_dev->bd_addr.address[2],
427 p_dev->bd_addr.address[1], p_dev->bd_addr.address[0]);
428 ev.u.create.rd_size = dscp_len;
429 ev.u.create.rd_data = p_dscp;
430 ev.u.create.bus = BUS_BLUETOOTH;
431 ev.u.create.vendor = vendor_id;
432 ev.u.create.product = product_id;
433 ev.u.create.version = version;
434 ev.u.create.country = ctry_code;
435 result = uhid_write(p_dev->fd, &ev);
437 APPL_TRACE_WARNING("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
438 p_dev->fd, dscp_len, result);
441 APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __FUNCTION__, result);
443 /* The HID report descriptor is corrupted. Close the driver. */