summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--btif/co/bta_hh_co.c57
-rw-r--r--btif/include/btif_hh.h1
-rw-r--r--btif/src/btif_hh.c2
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--;
}