Fix for Nyko playpad
Nyko playpad does not cmply with HID Device spec. NYKO gamepad
advertises as supporting virtual unplug but when virtual is sent
by host it responds with ERR_UNSUPPORTED_REQUEST. Modified BTIF
code to start a timer when VUP is issued and fire the timer if peer
does not respond.
Bug:8055549
Change-Id: I90db956fb243f1a518b00424b103ebf9f0a1b7f0
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index c77d597..f7b9f3d 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -23,6 +23,8 @@
#include <hardware/bt_hh.h>
#include <stdint.h>
#include "bta_hh_api.h"
+#include "btu.h"
+
/*******************************************************************************
** Constants & Macros
@@ -64,6 +66,8 @@
BT_HDR *p_buf;
UINT32 hh_poll_thread_id;
UINT8 hh_keep_polling;
+ BOOLEAN vup_timer_active;
+ TIMER_LIST_ENT vup_timer;
} btif_hh_device_t;
/* Control block to maintain properties of devices */
diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c
index 61dd894..e4da0be 100644
--- a/btif/src/btif_hh.c
+++ b/btif/src/btif_hh.c
@@ -73,6 +73,8 @@
#define BTIF_HH_ID_1 0
#define BTIF_HH_DEV_DISCONNECTED 3
+#define BTIF_TIMEOUT_VUP_SECS 3
+
#ifndef BTUI_HH_SECURITY
#define BTUI_HH_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
@@ -163,6 +165,7 @@
static void toggle_os_keylockstates(int fd, int changedkeystates);
static void sync_lockstate_on_connect(btif_hh_device_t *p_dev);
//static void hh_update_keyboard_lockstates(btif_hh_device_t *p_dev);
+void btif_hh_tmr_hdlr(TIMER_LIST_ENT *tle);
/************************************************************************************
@@ -404,6 +407,58 @@
/*******************************************************************************
**
+** Function btif_hh_stop_vup_timer
+**
+** Description stop vitual unplug timer
+**
+** Returns void
+*******************************************************************************/
+void btif_hh_stop_vup_timer(bt_bdaddr_t *bd_addr)
+{
+ btif_hh_device_t *p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if(p_dev != NULL)
+ {
+ if (p_dev->vup_timer_active)
+ {
+ BTIF_TRACE_DEBUG0("stop VUP timer ");
+ btu_stop_timer(&p_dev->vup_timer);
+ }
+ p_dev->vup_timer_active = FALSE;
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hh_start_vup_timer
+**
+** Description start virtual unplug timer
+**
+** Returns void
+*******************************************************************************/
+void btif_hh_start_vup_timer(bt_bdaddr_t *bd_addr)
+{
+ btif_hh_device_t *p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+
+ if (p_dev->vup_timer_active == FALSE)
+ {
+ BTIF_TRACE_DEBUG0("Start VUP timer ");
+ memset(&p_dev->vup_timer, 0, sizeof(TIMER_LIST_ENT));
+ p_dev->vup_timer.param = (UINT32)btif_hh_tmr_hdlr;
+ btu_start_timer(&p_dev->vup_timer, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_VUP_SECS);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("Restart VUP timer ");
+ btu_stop_timer(&p_dev->vup_timer);
+ btu_start_timer(&p_dev->vup_timer, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_VUP_SECS);
+ }
+ p_dev->vup_timer_active = TRUE;
+
+}
+
+/*******************************************************************************
+**
** Function btif_hh_add_added_dev
**
** Description Add a new device to the added device list.
@@ -545,6 +600,8 @@
&& (p_dev->attr_mask & HID_VIRTUAL_CABLE))
{
BTIF_TRACE_DEBUG1("%s Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG", __FUNCTION__);
+ /* start the timer */
+ btif_hh_start_vup_timer(bd_addr);
BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
return BT_STATUS_SUCCESS;
}
@@ -612,7 +669,7 @@
BD_ADDR *bda = (BD_ADDR*)bd_addr;
BTA_HhOpen(*bda, BTA_HH_PROTO_RPT_MODE, sec_mask);
}
- else
+ else
{
// This device shall be connected from the host side.
BTIF_TRACE_ERROR2("%s: Error, device %s can only be reconnected from device side",
@@ -647,7 +704,6 @@
BTIF_TRACE_DEBUG1("%s-- Error: device not connected:",__FUNCTION__);
}
-
/*******************************************************************************
**
** Function btif_btif_hh_setreport
@@ -799,6 +855,10 @@
hidreport[0]=1;
bta_hh_co_write(p_dev->fd , hidreport, sizeof(hidreport));
}
+ if(p_dev->vup_timer_active)
+ {
+ btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+ }
btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);
@@ -890,8 +950,9 @@
bdcpy(bda, p_dev->bd_addr.address);
btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info);
BTIF_TRACE_DEBUG6("BTA_HH_GET_DSCP_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
- p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
- p_dev->bd_addr.address[3], p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1],
+ p_dev->bd_addr.address[2],p_dev->bd_addr.address[3],
+ p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
BTA_HhAddDev(bda, p_dev->attr_mask,p_dev->sub_class,p_dev->app_id, dscp_info);
// write hid info to nvram
ret = btif_storage_add_hid_device_info(&(p_dev->bd_addr), p_dev->attr_mask,p_dev->sub_class,p_dev->app_id,
@@ -971,14 +1032,21 @@
btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
if (p_dev != NULL) {
BTIF_TRACE_DEBUG6("BTA_HH_VC_UNPLUG_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
- p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
- p_dev->bd_addr.address[3], p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1],
+ p_dev->bd_addr.address[2],p_dev->bd_addr.address[3],
+ p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ /* Stop the VUP timer */
+ if(p_dev->vup_timer_active)
+ {
+ btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+ }
p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
BTIF_TRACE_DEBUG1("%s---Sending connection state change", __FUNCTION__);
HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);
- BTIF_TRACE_DEBUG1("%s---Removing HID mouse bond", __FUNCTION__);
+ BTIF_TRACE_DEBUG1("%s---Removing HID bond", __FUNCTION__);
BTA_DmRemoveDevice((UINT8 *)p_dev->bd_addr.address);
- HAL_CBACK(bt_hh_callbacks, virtual_unplug_cb,&(p_dev->bd_addr),p_data->dev_status.status);
+ HAL_CBACK(bt_hh_callbacks, virtual_unplug_cb,&(p_dev->bd_addr),
+ p_data->dev_status.status);
}
break;
@@ -1086,6 +1154,46 @@
}
}
+/*******************************************************************************
+**
+** Function btif_hh_tmr_hdlr
+**
+** Description Process timer timeout
+**
+** Returns void
+*******************************************************************************/
+void btif_hh_tmr_hdlr(TIMER_LIST_ENT *tle)
+{
+ btif_hh_device_t *p_dev;
+ UINT8 i,j;
+ tBTA_HH_EVT event;
+ tBTA_HH p_data;
+ int param_len = 0;
+ memset(&p_data, 0, sizeof(tBTA_HH));
+
+ BTIF_TRACE_DEBUG2("%s timer_in_use=%d", __FUNCTION__, tle->in_use );
+
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED)
+ {
+
+ p_dev = &btif_hh_cb.devices[i];
+
+ if (p_dev->vup_timer_active)
+ {
+ p_dev->vup_timer_active = FALSE;
+ event = BTA_HH_VC_UNPLUG_EVT;
+ p_data.dev_status.status = BTHH_ERR;
+ p_data.dev_status.handle = p_dev->dev_handle;
+ param_len = sizeof(tBTA_HH_CBDATA);
+
+ /* switch context to btif task context */
+ btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (void*)&p_data,
+ param_len, NULL);
+ }
+ }
+ }
+}
/*******************************************************************************
**