diff options
-rw-r--r-- | btif/co/bta_hh_co.c | 57 | ||||
-rw-r--r-- | btif/include/btif_hh.h | 1 | ||||
-rw-r--r-- | btif/src/btif_hh.c | 2 |
3 files changed, 46 insertions, 14 deletions
diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c index 31dfde1ab..bd6fd6f06 100644 --- a/btif/co/bta_hh_co.c +++ b/btif/co/bta_hh_co.c @@ -43,11 +43,23 @@ const char *dev_path = "/dev/uhid"; static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX]; #endif +void uhid_set_non_blocking(int fd) +{ + int opts = fcntl(fd, F_GETFL); + if (opts < 0) + APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__, strerror(errno)); + + opts |= O_NONBLOCK; + + if (fcntl(fd, F_SETFL, opts) < 0) + APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__, strerror(errno)); +} + /*Internal function to perform UHID write and error checking*/ static int uhid_write(int fd, const struct uhid_event *ev) { - ssize_t ret; - ret = write(fd, ev, sizeof(*ev)); + ssize_t ret = write(fd, ev, sizeof(*ev)); + if (ret < 0){ int rtn = -errno; APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", @@ -57,9 +69,9 @@ static int uhid_write(int fd, const struct uhid_event *ev) APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu", __FUNCTION__, ret, sizeof(*ev)); return -EFAULT; - } else { - return 0; } + + return 0; } /* Internal function to parse the events received from UHID driver*/ @@ -82,24 +94,31 @@ static int uhid_event(btif_hh_device_t *p_dev) APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __FUNCTION__, strerror(errno)); return -errno; - } else if (ret < (ssize_t)sizeof(ev.type)) { - APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", + } else if ((ev.type == UHID_OUTPUT) || (ev.type==UHID_OUTPUT_EV)) { + // Only these two types havae payload, + // ensure we read full event descriptor + if (ret < (ssize_t)sizeof(ev)) { + APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %ld != %lu", __FUNCTION__, ret, sizeof(ev.type)); - return -EFAULT; + return -EFAULT; + } } switch (ev.type) { case UHID_START: APPL_TRACE_DEBUG("UHID_START from uhid-dev\n"); + p_dev->ready_for_data = TRUE; break; case UHID_STOP: APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n"); + p_dev->ready_for_data = FALSE; break; case UHID_OPEN: APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n"); break; case UHID_CLOSE: APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n"); + p_dev->ready_for_data = FALSE; break; case UHID_OUTPUT: if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) { @@ -175,14 +194,17 @@ static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg *******************************************************************************/ static void *btif_hh_poll_event_thread(void *arg) { - btif_hh_device_t *p_dev = arg; APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd); struct pollfd pfds[1]; int ret; + pfds[0].fd = p_dev->fd; pfds[0].events = POLLIN; + // Set the uhid fd as non-blocking to ensure we never block the BTU thread + uhid_set_non_blocking(p_dev->fd); + while(p_dev->hh_keep_polling){ ret = poll(pfds, 1, 50); if (ret < 0) { @@ -224,7 +246,8 @@ void bta_hh_co_destroy(int fd) int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len) { - APPL_TRACE_DEBUG("bta_hh_co_data: UHID write"); + APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len); + struct uhid_event ev; memset(&ev, 0, sizeof(ev)); ev.type = UHID_INPUT; @@ -235,6 +258,7 @@ int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len) return -1; } memcpy(ev.u.input.data, rpt, len); + return uhid_write(fd, &ev); } @@ -280,9 +304,11 @@ void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_ma if (p_dev->fd < 0){ APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __FUNCTION__,strerror(errno)); + return; }else APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd); } + p_dev->hh_keep_polling = 1; p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev); break; @@ -307,6 +333,7 @@ void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_ma if (p_dev->fd < 0){ APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __FUNCTION__,strerror(errno)); + return; }else{ APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd); p_dev->hh_keep_polling = 1; @@ -397,11 +424,13 @@ void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MO APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle); return; } - // Send the HID report to the kernel. - if (p_dev->fd >= 0) { + + // Send the HID data to the kernel. + if ((p_dev->fd >= 0) && p_dev->ready_for_data) { bta_hh_co_write(p_dev->fd, p_rpt, len); }else { - APPL_TRACE_WARNING("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len); + APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __FUNCTION__, p_dev->fd, + p_dev->ready_for_data, len); } } @@ -437,7 +466,7 @@ void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 ven vendor_id, product_id, version, ctry_code); -//Create and send hid descriptor to kernel + //Create and send hid descriptor to kernel memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1); @@ -455,7 +484,7 @@ void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 ven ev.u.create.country = ctry_code; result = uhid_write(p_dev->fd, &ev); - APPL_TRACE_WARNING("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__, + APPL_TRACE_WARNING("%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __FUNCTION__, p_dev->fd, dscp_len, result); if (result) { diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h index dc34d653c..1088c53bf 100644 --- a/btif/include/btif_hh.h +++ b/btif/include/btif_hh.h @@ -64,6 +64,7 @@ typedef struct UINT8 sub_class; UINT8 app_id; int fd; + BOOLEAN ready_for_data; pthread_t hh_poll_thread_id; UINT8 hh_keep_polling; BOOLEAN vup_timer_active; diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c index 3b9220aef..633975d5d 100644 --- a/btif/src/btif_hh.c +++ b/btif/src/btif_hh.c @@ -527,6 +527,8 @@ void btif_hh_remove_device(bt_bdaddr_t bd_addr) p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN; p_dev->dev_handle = BTA_HH_INVALID_HANDLE; + p_dev->ready_for_data = FALSE; + if (btif_hh_cb.device_num > 0) { btif_hh_cb.device_num--; } |