summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bta/hd/bta_hd_act.c1329
-rw-r--r--bta/hd/bta_hd_api.c495
-rw-r--r--bta/hd/bta_hd_int.h417
-rw-r--r--bta/hd/bta_hd_main.c587
-rw-r--r--bta/include/bta_hd_api.h558
-rw-r--r--btif/include/btif_hd.h112
-rw-r--r--btif/src/btif_hd.c1820
-rw-r--r--stack/hid/hidd_api.c599
-rw-r--r--stack/hid/hidd_conn.c1043
-rw-r--r--stack/hid/hidd_int.h94
-rw-r--r--stack/include/hidd_api.h236
11 files changed, 7290 insertions, 0 deletions
diff --git a/bta/hd/bta_hd_act.c b/bta/hd/bta_hd_act.c
new file mode 100644
index 000000000..8ec26981e
--- /dev/null
+++ b/bta/hd/bta_hd_act.c
@@ -0,0 +1,1329 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID host action functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "bta_hh_int.h"
+#include "bta_hh_co.h"
+#include "utl.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event,
+ UINT32 data, BT_HDR *pdata);
+static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result);
+
+#if BTA_HH_DEBUG
+static char* bta_hh_get_w4_event(UINT16 event);
+static char * bta_hh_hid_event_name(UINT16 event);
+#endif
+
+/*****************************************************************************
+** Action Functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_hh_api_enable
+**
+** Description Perform necessary operations to enable HID host.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_api_enable(tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_STATUS status = BTA_HH_ERR;
+ UINT8 xx;
+
+ /* initialize BTE HID */
+ HID_HostInit();
+
+ memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+
+ HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask);
+
+ /* Register with L2CAP */
+ if ( HID_HostRegister (bta_hh_cback) == HID_SUCCESS)
+ {
+ /* store parameters */
+ bta_hh_cb.p_cback = p_data->api_enable.p_cback;
+
+ status = BTA_HH_OK;
+ /* initialize device CB */
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++)
+ {
+ bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST;
+ bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE;
+ bta_hh_cb.kdev[xx].index = xx;
+ }
+
+ /* initialize control block map */
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++)
+ bta_hh_cb.cb_index[xx] = BTA_HH_IDX_INVALID;
+ }
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (status == BTA_HH_OK)
+ {
+ bta_hh_le_enable();
+ }
+ else
+#endif
+ /* signal BTA call back event */
+ (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status);
+}
+/*******************************************************************************
+**
+** Function bta_hh_api_disable
+**
+** Description Perform necessary operations to disable HID host.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_api_disable(void)
+{
+ UINT8 xx;
+
+ /* service is not enabled */
+ if (bta_hh_cb.p_cback == NULL)
+ return;
+
+ /* no live connection, signal DISC_CMPL_EVT directly */
+ if (!bta_hh_cb.cnt_num)
+ {
+ bta_hh_disc_cmpl();
+ }
+ else /* otherwise, disconnect all live connections */
+ {
+ bta_hh_cb.w4_disable = TRUE;
+
+ for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++)
+ {
+ /* send API_CLOSE event to every connected device */
+ if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST )
+ {
+ /* disconnect all connected devices */
+ bta_hh_sm_execute(&bta_hh_cb.kdev[xx],
+ BTA_HH_API_CLOSE_EVT,
+ NULL);
+ }
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_disc_cmpl
+**
+** Description All connections have been closed, disable service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_disc_cmpl(void)
+{
+ tBTA_HH_STATUS status = BTA_HH_OK;
+
+ /* Deregister with lower layer */
+ if (HID_HostDeregister()!= HID_SUCCESS)
+ status = BTA_HH_ERR;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ bta_hh_le_deregister();
+ return;
+#endif
+
+ bta_hh_cleanup_disable(status);
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_sdp_cback
+**
+** Description SDP callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask,
+ tHID_DEV_SDP_INFO *sdp_rec )
+{
+ tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur;
+ UINT8 hdl;
+ tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+
+ /* make sure sdp succeeded and hh has not been disabled */
+ if ((result == SDP_SUCCESS) && (p_cb != NULL))
+ {
+ /* security is required for the connection, add attr_mask bit*/
+ if (p_cb->sec_mask)
+ attr_mask |= HID_SEC_REQUIRED;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT4("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \
+ attr_mask 0x%02x, handle %x", \
+ p_cb, result, attr_mask,p_cb->hid_handle);
+#endif
+
+ /* check to see type of device is supported , and should not been added before */
+ if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class))
+ {
+ /* if not added before */
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
+ {
+ /* add device/update attr_mask information */
+ if(HID_HostAddDev (p_cb->addr, attr_mask, &hdl) == HID_SUCCESS)
+ {
+ status = BTA_HH_OK;
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[hdl] = p_cb->index;
+ }
+ else
+ {
+ p_cb->app_id = 0;
+ }
+ }
+ else
+ {
+ hdl = p_cb->hid_handle;
+ }
+ /* else : incoming connection after SDP should update the SDP information as well */
+
+ if (p_cb->app_id != 0)
+ {
+ /* update cb information with attr_mask, dscp_info etc. */
+ bta_hh_add_device_to_list(p_cb, hdl, attr_mask,
+ &sdp_rec->dscp_info,
+ sdp_rec->sub_class,
+ sdp_rec->ssr_max_latency,
+ sdp_rec->ssr_min_tout,
+ p_cb->app_id);
+
+ p_cb->dscp_info.ctry_code = sdp_rec->ctry_code;
+
+ status = BTA_HH_OK;
+ }
+
+ }
+ else /* type of device is not supported */
+ status = BTA_HH_ERR_TOD_UNSPT;
+ }
+
+ /* free disc_db when SDP is completed */
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+
+ /* send SDP_CMPL_EVT into state machine */
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_di_sdp_cback
+**
+** Description SDP DI callback function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_di_sdp_cback(UINT16 result)
+{
+ tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur;
+ tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+ tSDP_DI_GET_RECORD di_rec;
+ tHID_STATUS ret;
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT2("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result);
+#endif
+
+ /* if DI record does not exist on remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be
+ * set to 0xffff and we will allow the connection to go through. Spec mandates that DI
+ * record be set, but many HID devices do not set this. So for IOP purposes, we allow the
+ * connection to go through and update the DI record to invalid DI entry.*/
+ if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL))
+ {
+ if(result == SDP_SUCCESS && SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0)
+ {
+ /* always update information with primary DI record */
+ if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS)
+ {
+ bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0);
+ }
+
+ }
+ else /* no DI recrod available */
+ {
+ bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0);
+ }
+
+ if ((ret = HID_HostGetSDPRecord(p_cb->addr,
+ bta_hh_cb.p_disc_db,
+ p_bta_hh_cfg->sdp_db_size,
+ bta_hh_sdp_cback)) == HID_SUCCESS)
+ {
+ status = BTA_HH_OK;
+ }
+ else
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_di_sdp_cback: HID_HostGetSDPRecord failed: Status 0x%2x",
+ ret);
+#endif
+ }
+ }
+
+
+ if (status != BTA_HH_OK)
+ {
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+ /* send SDP_CMPL_EVT into state machine */
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+ }
+ return;
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_start_sdp
+**
+** Description Start SDP service search, and obtain necessary SDP records.
+** Only one SDP service search request is allowed at the same
+** time. For every BTA_HhOpen API call, do SDP first unless SDP
+** has been done previously.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+ UINT8 hdl;
+
+ p_cb->sec_mask = p_data->api_conn.sec_mask;
+ p_cb->mode = p_data->api_conn.mode;
+ bta_hh_cb.p_cur = p_cb;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr))
+ {
+ bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr);
+ return;
+ }
+#endif
+
+ /* if previously virtually cabled device, skip SDP */
+ if (p_cb->app_id)
+ {
+ status = BTA_HH_OK;
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG0("bta_hh_start_sdp:: skip SDP for known devices");
+#endif
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
+ {
+ if (HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl) \
+ == HID_SUCCESS)
+ {
+ /* update device CB with newly register device handle */
+ bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL,
+ p_cb->sub_class,
+ p_cb->dscp_info.ssr_max_latency,
+ p_cb->dscp_info.ssr_min_tout,
+ p_cb->app_id);
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[hdl] = p_cb->index;
+ }
+ else
+ status = BTA_HH_ERR_NO_RES;
+ }
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+
+ return;
+ }
+ /* GetSDPRecord. at one time only one SDP precedure can be active */
+ else if (!bta_hh_cb.p_disc_db)
+ {
+ bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(p_bta_hh_cfg->sdp_db_size);
+
+ if (bta_hh_cb.p_disc_db == NULL)
+ {
+ status = BTA_HH_ERR_NO_RES;
+ }
+ else
+ {
+ bta_hh_cb.p_cur = p_cb;
+ /* do DI discovery first */
+ if (SDP_DiDiscover(p_data->api_conn.bd_addr,
+ bta_hh_cb.p_disc_db,
+ p_bta_hh_cfg->sdp_db_size,
+ bta_hh_di_sdp_cback) != SDP_SUCCESS)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_start_sdp: SDP_DiDiscover failed: \
+ Status 0x%2X",status);
+#endif
+ status = BTA_HH_ERR_SDP;
+ utl_freebuf((void **)&bta_hh_cb.p_disc_db);
+ }
+ else
+ status = BTA_HH_OK;
+ }
+ }
+
+ if (status != BTA_HH_OK)
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+
+ return;
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_sdp_cmpl
+**
+** Description When SDP completed, initiate a connection or report error depend
+** on SDP result.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn_dat;
+ tBTA_HH_STATUS status = p_data->status;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl: status 0x%2X",p_data->status);
+#endif
+
+ /* initialize call back data */
+ memset((void *)&conn_dat, 0, sizeof(tBTA_HH_CONN));
+ conn_dat.handle = p_cb->hid_handle;
+ bdcpy(conn_dat.bda, p_cb->addr);
+
+ /* if SDP compl success */
+ if ( status == BTA_HH_OK)
+ {
+ /* not incoming connection doing SDP, initiate a HID connection */
+ if (!p_cb->incoming_conn)
+ {
+ tHID_STATUS ret;
+ /* set security level */
+ HID_HostSetSecurityLevel("", p_cb->sec_mask);
+
+ /* open HID connection */
+ if ((ret = HID_HostOpenDev (p_cb->hid_handle)) != HID_SUCCESS)
+ {
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl: HID_HostOpenDev failed: \
+ Status 0x%2X",ret);
+#endif
+ /* open fail, remove device from management device list */
+ HID_HostRemoveDev( p_cb->hid_handle);
+ status = BTA_HH_ERR;
+ }
+ else
+ {
+ status = BTA_HH_OK;
+ }
+ }
+ else /* incoming connection SDP finish */
+ {
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+ }
+ }
+
+ if (status != BTA_HH_OK)
+ {
+ /* Check if this was incoming connection request from an unknown device
+ **and connection failed due to missing HID Device SDP UUID
+ **In above condition, disconnect the link as well as remove the
+ **device from list of HID devices*/
+ if ((status == BTA_HH_ERR_SDP) &&
+ (p_cb->incoming_conn) &&(p_cb->app_id == 0))
+ {
+ APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl:SDP failed for incoming conn :hndl %d",
+ p_cb->incoming_hid_handle);
+ HID_HostRemoveDev( p_cb->incoming_hid_handle);
+ }
+ conn_dat.status = status;
+ (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+ /* move state machine W4_CONN ->IDLE */
+ bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+
+ /* if this is an outgoing connection to an unknown device, clean up cb */
+ if (p_cb->app_id == 0 && !p_cb->incoming_conn)
+ {
+ /* clean up device control block */
+ bta_hh_clean_up_kdev(p_cb);
+ }
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_api_disc_act
+**
+** Description HID Host initiate a disconnection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CBDATA disc_dat;
+ tHID_STATUS status;
+
+#if BTA_HH_LE_INCLUDED == TRUE
+ if (p_cb->is_le_device)
+ bta_hh_le_api_disc_act(p_cb);
+ else
+#endif
+ {
+ /* found an active connection */
+ disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle;
+ disc_dat.status = BTA_HH_ERR;
+
+ status = HID_HostCloseDev(disc_dat.handle);
+
+ if (status)
+ (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat);
+ }
+
+ return;
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_open_cmpl_act
+**
+** Description HID host connection completed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn ;
+ UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \
+ p_cb->hid_handle;
+
+ memset((void *)&conn, 0, sizeof (tBTA_HH_CONN));
+ conn.handle = dev_handle;
+ bdcpy(conn.bda, p_cb->addr);
+
+ /* increase connection number */
+ bta_hh_cb.cnt_num ++;
+
+ /* initialize device driver */
+ bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class,
+ p_cb->attr_mask, p_cb->app_id);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ conn.status = p_cb->status;
+ conn.le_hid = p_cb->is_le_device;
+ conn.scps_supported = p_cb->scps_supported;
+
+ if (!p_cb->is_le_device)
+#endif
+ {
+ /* inform role manager */
+ bta_sys_conn_open( BTA_ID_HH ,p_cb->app_id, p_cb->addr);
+ }
+ /* set protocol mode when not default report mode */
+ if ( p_cb->mode != BTA_HH_PROTO_RPT_MODE
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ && !p_cb->is_le_device
+#endif
+ )
+ {
+ if ((HID_HostWriteDev(dev_handle,
+ HID_TRANS_SET_PROTOCOL, HID_PAR_PROTOCOL_BOOT_MODE,
+ 0,
+ 0, NULL)) != HID_SUCCESS)
+ {
+ /* HID connection is up, while SET_PROTO fail */
+ conn.status = BTA_HH_ERR_PROTO;
+ (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn);
+ }
+ else
+ {
+ conn.status = BTA_HH_OK;
+ p_cb->w4_evt = BTA_HH_OPEN_EVT;
+ }
+ }
+ else
+ (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn);
+
+ p_cb->incoming_conn = FALSE;
+ p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_open_act
+**
+** Description HID host receive HID_OPEN_EVT .
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_API_CONN conn_data;
+
+ UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \
+ p_cb->hid_handle;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_EVENT1 ("bta_hh_open_act: Device[%d] connected", dev_handle);
+#endif
+
+ /* SDP has been done */
+ if (p_cb->app_id != 0)
+ {
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
+ }
+ else
+ /* app_id == 0 indicates an incoming conenction request arrives without SDP
+ performed, do it first */
+ {
+ p_cb->incoming_conn = TRUE;
+ /* store the handle here in case sdp fails - need to disconnect */
+ p_cb->incoming_hid_handle = dev_handle;
+
+ memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN));
+ bdcpy(conn_data.bd_addr, p_cb->addr);
+ bta_hh_start_sdp(p_cb, (tBTA_HH_DATA *)&conn_data);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_data_act
+**
+** Description HID Host process a data report
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
+{
+ BT_HDR *pdata = p_data->hid_cback.p_data;
+ UINT8 *p_rpt = (UINT8 *)(pdata + 1) + pdata->offset;
+
+ bta_hh_co_data((UINT8)p_data->hid_cback.hdr.layer_specific, p_rpt, pdata->len,
+ p_cb->mode, p_cb->sub_class, p_cb->dscp_info.ctry_code, p_cb->addr, p_cb->app_id);
+
+ utl_freebuf((void **)&pdata);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_handsk_act
+**
+** Description HID Host process a handshake acknoledgement.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
+{
+ tBTA_HH_CBDATA cback_data ;
+ tBTA_HH_HSDATA hs_data;
+ tBTA_HH_CONN conn ;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("HANDSHAKE received for: event = %s data= %d",
+ bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data);
+#endif
+
+ memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA));
+ memset(&cback_data, 0, sizeof(tBTA_HH_CBDATA));
+
+ switch (p_cb->w4_evt)
+ {
+ /* GET_ transsaction, handshake indicate unsupported request */
+ case BTA_HH_GET_PROTO_EVT:
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
+ /* fall through */
+ case BTA_HH_GET_RPT_EVT:
+ case BTA_HH_GET_IDLE_EVT :
+ hs_data.handle = p_cb->hid_handle;
+ /* if handshake gives an OK code for these transaction, fill in UNSUPT */
+ if ((hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data)) == BTA_HH_OK)
+ hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
+
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data);
+ p_cb->w4_evt = 0;
+ break;
+
+ /* acknoledgement from HID device for SET_ transaction */
+ case BTA_HH_SET_RPT_EVT:
+ case BTA_HH_SET_PROTO_EVT:
+ case BTA_HH_SET_IDLE_EVT :
+ cback_data.handle = p_cb->hid_handle;
+ cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data);
+ p_cb->w4_evt = 0;
+ break;
+
+ /* SET_PROTOCOL when open connection */
+ case BTA_HH_OPEN_EVT:
+ conn.status =p_data->hid_cback.data ? BTA_HH_ERR_PROTO: BTA_HH_OK;
+ conn.handle = p_cb->hid_handle;
+ bdcpy(conn.bda, p_cb->addr);
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn);
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ p_cb->w4_evt = 0;
+ break;
+
+ default:
+ /* unknow transaction handshake response */
+ APPL_TRACE_DEBUG0("unknown transaction type");
+ break;
+ }
+
+ /* transaction achknoledgement received, inform PM for mode change */
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_ctrl_dat_act
+**
+** Description HID Host process a data report from control channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data)
+{
+ BT_HDR *pdata = p_data->hid_cback.p_data;
+ UINT8 *data = (UINT8 *)(pdata + 1) + pdata->offset;
+ tBTA_HH_HSDATA hs_data;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("Ctrl DATA received w4: event[%s]",
+ bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+ hs_data.status = BTA_HH_OK;
+ hs_data.handle = p_cb->hid_handle;
+
+ switch (p_cb->w4_evt)
+ {
+ case BTA_HH_GET_IDLE_EVT:
+ hs_data.rsp_data.idle_rate = *data;
+ break;
+ case BTA_HH_GET_RPT_EVT:
+ hs_data.rsp_data.p_rpt_data = pdata;
+ break;
+ case BTA_HH_GET_PROTO_EVT:
+ /* match up BTE/BTA report/boot mode def*/
+ hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)? \
+ BTA_HH_PROTO_RPT_MODE : BTA_HH_PROTO_BOOT_MODE;
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("GET_PROTOCOL Mode = [%s]",
+ (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)? "Report" : "Boot");
+#endif
+ break;
+ /* should not expect control DATA for SET_ transaction */
+ case BTA_HH_SET_PROTO_EVT:
+ /* fall through */
+ case BTA_HH_SET_RPT_EVT:
+ /* fall through */
+ case BTA_HH_SET_IDLE_EVT :
+ /* fall through */
+ default:
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("invalid transaction type for DATA payload: 4_evt[%s]",
+ bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+ break;
+ }
+
+ /* inform PM for mode change */
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+
+ (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data);
+
+ p_cb->w4_evt = 0;
+ utl_freebuf((void **)&pdata);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_open_failure
+**
+** Description report HID open failure when at wait for connection state and receive
+** device close event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn_dat ;
+ UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+ memset(&conn_dat, 0, sizeof(tBTA_HH_CONN));
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
+ BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseDev(p_cb->hid_handle);
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ /* clean up control block, but retain SDP info and device handle */
+ p_cb->vp = FALSE;
+ p_cb->w4_evt = 0;
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable)
+ {
+ bta_hh_disc_cmpl();
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_close_act
+**
+** Description HID Host process a close event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CONN conn_dat ;
+ tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+ UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+ /* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */
+ UINT16 event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;
+
+ disc_dat.handle = p_cb->hid_handle;
+ disc_dat.status = p_data->hid_cback.data;
+
+ /* Check reason for closing */
+ if ((reason & (HID_L2CAP_CONN_FAIL|HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection (page timeout or l2cap error) */
+ (reason == HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */
+ (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */
+ {
+ /* Failure in opening connection */
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseDev(p_cb->hid_handle);
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ return;
+ }
+ /* otherwise report CLOSE/VC_UNPLUG event */
+ else
+ {
+ /* finaliza device driver */
+ bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+ /* inform role manager */
+ bta_sys_conn_close( BTA_ID_HH ,p_cb->app_id, p_cb->addr);
+ /* update total conn number */
+ bta_hh_cb.cnt_num --;
+
+ if (disc_dat.status)
+ disc_dat.status = BTA_HH_ERR;
+
+ (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&disc_dat);
+
+ /* if virtually unplug, remove device */
+ if (p_cb->vp )
+ {
+ HID_HostRemoveDev( p_cb->hid_handle);
+ bta_hh_clean_up_kdev(p_cb);
+ }
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ }
+
+ /* clean up control block, but retain SDP info and device handle */
+ p_cb->vp = FALSE;
+ p_cb->w4_evt = 0;
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable)
+ {
+ bta_hh_disc_cmpl();
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_get_dscp_act
+**
+** Description Get device report descriptor
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ UNUSED(p_data);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_cb->is_le_device)
+ {
+ bta_hh_le_get_dscp_act(p_cb);
+ }
+ else
+#endif
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info);
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_maint_dev_act
+**
+** Description HID Host maintain device list.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_MAINT_DEV *p_dev_info = &p_data->api_maintdev;
+ tBTA_HH_DEV_INFO dev_info ;
+ UINT8 dev_handle;
+
+ dev_info.status = BTA_HH_ERR;
+ dev_info.handle = BTA_HH_INVALID_HANDLE;
+
+ switch (p_dev_info->sub_event)
+ {
+ case BTA_HH_ADD_DEV_EVT: /* add a device */
+ bdcpy(dev_info.bda, p_dev_info->bda);
+ /* initialize callback data */
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
+ {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr))
+ {
+ dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info);
+ dev_info.status = BTA_HH_OK;
+ }
+ else
+#endif
+
+ if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\
+ == HID_SUCCESS)
+ {
+ dev_info.handle = dev_handle;
+ dev_info.status = BTA_HH_OK;
+
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ /* update DI information */
+ bta_hh_update_di_info(p_cb,
+ p_dev_info->dscp_info.vendor_id,
+ p_dev_info->dscp_info.product_id,
+ p_dev_info->dscp_info.version,
+ p_dev_info->dscp_info.flag);
+#else
+ bta_hh_update_di_info(p_cb,
+ p_dev_info->dscp_info.vendor_id,
+ p_dev_info->dscp_info.product_id,
+ p_dev_info->dscp_info.version,
+ 0);
+
+#endif
+ /* add to BTA device list */
+ bta_hh_add_device_to_list(p_cb, dev_handle,
+ p_dev_info->attr_mask,
+ &p_dev_info->dscp_info.descriptor,
+ p_dev_info->sub_class,
+ p_dev_info->dscp_info.ssr_max_latency,
+ p_dev_info->dscp_info.ssr_min_tout,
+ p_dev_info->app_id);
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[dev_handle] = p_cb->index;
+ }
+ }
+ else /* device already been added */
+ {
+ dev_info.handle = p_cb->hid_handle;
+ dev_info.status = BTA_HH_OK;
+ }
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+
+ break;
+ case BTA_HH_RMV_DEV_EVT: /* remove device */
+ dev_info.handle = (UINT8)p_dev_info->hdr.layer_specific;
+ bdcpy(dev_info.bda, p_cb->addr);
+
+#if BTA_HH_LE_INCLUDED == TRUE
+ if (p_cb->is_le_device)
+ {
+ bta_hh_le_remove_dev_bg_conn(p_cb);
+ bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+ bta_hh_clean_up_kdev(p_cb);
+ }
+ else
+#endif
+ {
+ if(HID_HostRemoveDev( dev_info.handle ) == HID_SUCCESS)
+ {
+ dev_info.status = BTA_HH_OK;
+
+ /* remove from known device list in BTA */
+ bta_hh_clean_up_kdev(p_cb);
+ }
+ }
+ break;
+
+ default:
+ APPL_TRACE_DEBUG0("invalid command");
+ break;
+ }
+
+ (* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info);
+}
+/*******************************************************************************
+**
+** Function bta_hh_write_dev_act
+**
+** Description Write device action. can be SET/GET/DATA transaction.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+ tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
+ UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+
+#if BTA_HH_LE_INCLUDED == TRUE
+ if (p_cb->is_le_device)
+ bta_hh_le_write_dev_act(p_cb, p_data);
+ else
+#endif
+ {
+
+ cbdata.handle = p_cb->hid_handle;
+
+ /* match up BTE/BTA report/boot mode def */
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL)
+ {
+ p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\
+ HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE;
+ }
+
+ if (HID_HostWriteDev (p_cb->hid_handle,
+ p_data->api_sndcmd.t_type,
+ p_data->api_sndcmd.param,
+ p_data->api_sndcmd.data,
+ p_data->api_sndcmd.rpt_id,
+ p_data->api_sndcmd.p_data) != HID_SUCCESS)
+ {
+ APPL_TRACE_ERROR0("HID_HostWriteDev Error ");
+ cbdata.status = BTA_HH_ERR;
+
+ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
+ p_data->api_sndcmd.t_type != HID_TRANS_DATA)
+ (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
+ }
+ else
+ {
+
+ switch(p_data->api_sndcmd.t_type)
+ {
+ case HID_TRANS_SET_PROTOCOL:
+ /* fall through */
+ case HID_TRANS_GET_REPORT:
+ /* fall through */
+ case HID_TRANS_SET_REPORT:
+ /* fall through */
+ case HID_TRANS_GET_PROTOCOL:
+ /* fall through */
+ case HID_TRANS_GET_IDLE:
+ /* fall through */
+ case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */
+ p_cb->w4_evt = event;
+ break;
+ case HID_TRANS_DATA: /* output report */
+ /* fall through */
+ case HID_TRANS_CONTROL:
+ /* no handshake event will be generated */
+ /* if VC_UNPLUG is issued, set flag */
+ if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ p_cb->vp = TRUE;
+
+ break;
+ /* currently not expected */
+ case HID_TRANS_DATAC:
+ default:
+ APPL_TRACE_DEBUG1("bta_hh_write_dev_act:: cmd type = %d",
+ p_data->api_sndcmd.t_type);
+ break;
+ }
+
+ /* if not control type transaction, notify PM for energy control */
+ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
+ {
+ /* inform PM for mode change */
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND)
+ {
+ bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
+ {
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ }
+
+ }
+ return;
+}
+
+/*****************************************************************************
+** Static Function
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function bta_hh_cback
+**
+** Description BTA HH callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event,
+ UINT32 data, BT_HDR *pdata)
+{
+ tBTA_HH_CBACK_DATA *p_buf = NULL;
+ UINT16 sm_event = BTA_HH_INVALID_EVT;
+ UINT8 xx = 0;
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG1("bta_hh_cback::HID_event [%s]", bta_hh_hid_event_name(event));
+#endif
+
+ switch (event)
+ {
+ case HID_HDEV_EVT_OPEN:
+ sm_event = BTA_HH_INT_OPEN_EVT;
+ break;
+ case HID_HDEV_EVT_CLOSE:
+ sm_event = BTA_HH_INT_CLOSE_EVT;
+ break;
+ case HID_HDEV_EVT_INTR_DATA:
+ sm_event = BTA_HH_INT_DATA_EVT;
+ break;
+ case HID_HDEV_EVT_HANDSHAKE:
+ sm_event = BTA_HH_INT_HANDSK_EVT;
+ break;
+ case HID_HDEV_EVT_CTRL_DATA:
+ sm_event = BTA_HH_INT_CTRL_DATA;
+ break;
+ case HID_HDEV_EVT_RETRYING:
+ break;
+ case HID_HDEV_EVT_INTR_DATC:
+ case HID_HDEV_EVT_CTRL_DATC:
+ /* Unhandled events: Free buffer for DATAC */
+ utl_freebuf((void **)&pdata);
+ break;
+ case HID_HDEV_EVT_VC_UNPLUG:
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++)
+ {
+ if (bta_hh_cb.kdev[xx].hid_handle == dev_handle)
+ {
+ bta_hh_cb.kdev[xx].vp = TRUE;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (sm_event != BTA_HH_INVALID_EVT &&
+ (p_buf = (tBTA_HH_CBACK_DATA *)GKI_getbuf(sizeof(tBTA_HH_CBACK_DATA) +
+ sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->hdr.event = sm_event;
+ p_buf->hdr.layer_specific = (UINT16)dev_handle;
+ p_buf->data = data;
+ bdcpy(p_buf->addr, addr);
+ p_buf->p_data = pdata;
+
+ bta_sys_sendmsg(p_buf);
+ }
+
+}
+/*******************************************************************************
+**
+** Function bta_hh_get_trans_status
+**
+** Description translate a handshake result code into BTA HH
+** status code
+**
+*******************************************************************************/
+static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result)
+{
+ switch(result)
+ {
+ case HID_PAR_HANDSHAKE_RSP_SUCCESS : /* (0) */
+ return BTA_HH_OK;
+ case HID_PAR_HANDSHAKE_RSP_NOT_READY : /* (1) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID: /* (2) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ : /* (3) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM : /* (4) */
+ return (tBTA_HH_STATUS)result;
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN : /* (14) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_FATAL : /* (15) */
+ default:
+ return BTA_HH_HS_ERROR;
+ break;
+ }
+}
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+
+#if (defined BTA_HH_DEBUG && BTA_HH_DEBUG == TRUE)
+static char* bta_hh_get_w4_event(UINT16 event)
+{
+ switch (event)
+ {
+ case BTA_HH_GET_RPT_EVT:
+ return "BTA_HH_GET_RPT_EVT";
+ case BTA_HH_SET_RPT_EVT:
+ return "BTA_HH_SET_RPT_EVT";
+ case BTA_HH_GET_PROTO_EVT:
+ return "BTA_HH_GET_PROTO_EVT";
+ case BTA_HH_SET_PROTO_EVT:
+ return "BTA_HH_SET_PROTO_EVT";
+ case BTA_HH_GET_IDLE_EVT:
+ return "BTA_HH_GET_IDLE_EVT";
+ case BTA_HH_SET_IDLE_EVT:
+ return "BTA_HH_SET_IDLE_EVT";
+ case BTA_HH_OPEN_EVT:
+ return "BTA_HH_OPEN_EVT";
+ default:
+ return "Unknown event";
+ }
+
+}
+
+static char * bta_hh_hid_event_name(UINT16 event)
+{
+ switch (event)
+ {
+ case HID_HDEV_EVT_OPEN:
+ return "HID_HDEV_EVT_OPEN";
+ case HID_HDEV_EVT_CLOSE:
+ return "HID_HDEV_EVT_CLOSE";
+ case HID_HDEV_EVT_RETRYING:
+ return "HID_HDEV_EVT_RETRYING";
+ case HID_HDEV_EVT_INTR_DATA:
+ return "HID_HDEV_EVT_INTR_DATA";
+ case HID_HDEV_EVT_INTR_DATC:
+ return "HID_HDEV_EVT_INTR_DATC";
+ case HID_HDEV_EVT_CTRL_DATA:
+ return "HID_HDEV_EVT_CTRL_DATA";
+ case HID_HDEV_EVT_CTRL_DATC:
+ return "HID_HDEV_EVT_CTRL_DATC";
+ case HID_HDEV_EVT_HANDSHAKE:
+ return "HID_HDEV_EVT_HANDSHAKE";
+ case HID_HDEV_EVT_VC_UNPLUG:
+ return "HID_HDEV_EVT_VC_UNPLUG";
+ default:
+ return "Unknown HID event";
+ }
+}
+#endif
+#endif /* BTA_HH_INCLUDED */
+
diff --git a/bta/hd/bta_hd_api.c b/bta/hd/bta_hd_api.c
new file mode 100644
index 000000000..df41a5275
--- /dev/null
+++ b/bta/hd/bta_hd_api.c
@@ -0,0 +1,495 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID HOST API in the subsystem of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+#include "l2c_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_hh_reg =
+{
+ bta_hh_hdl_event,
+ BTA_HhDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_HhEnable
+**
+** Description Enable the HID host. This function must be called before
+** any other functions in the HID host API are called. When the
+** enable operation is complete the callback function will be
+** called with BTA_HH_ENABLE_EVT.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback)
+{
+ tBTA_HH_API_ENABLE *p_buf;
+
+ /* register with BTA system manager */
+ GKI_sched_lock();
+ bta_sys_register(BTA_ID_HH, &bta_hh_reg);
+ GKI_sched_unlock();
+
+ APPL_TRACE_ERROR0("Calling BTA_HhEnable");
+ p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE));
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE));
+
+ p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->sec_mask = sec_mask;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhDisable
+**
+** Description Disable the HID host. If the server is currently
+** connected, the connection will be closed.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhDisable(void)
+{
+ BT_HDR *p_buf;
+
+ bta_sys_deregister(BTA_ID_HH);
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_HH_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhClose
+**
+** Description Disconnect a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhClose(UINT8 dev_handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(BT_HDR));
+ p_buf->event = BTA_HH_API_CLOSE_EVT;
+ p_buf->layer_specific = (UINT16) dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhOpen
+**
+** Description Connect to a device of specified BD address in specified
+** protocol mode and security level.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, tBTA_SEC sec_mask)
+{
+ tBTA_HH_API_CONN *p_buf;
+
+ p_buf = (tBTA_HH_API_CONN *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_CONN));
+
+ if (p_buf!= NULL)
+ {
+ memset((void *)p_buf, 0, sizeof(tBTA_HH_API_CONN));
+
+ p_buf->hdr.event = BTA_HH_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+ p_buf->sec_mask = sec_mask;
+ p_buf->mode = mode;
+ bdcpy(p_buf->bd_addr, dev_bda);
+
+ bta_sys_sendmsg((void *)p_buf);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("No resource to send HID host Connect request.");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_snd_write_dev
+**
+*******************************************************************************/
+static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param,
+ UINT16 data, UINT8 rpt_id, BT_HDR *p_data)
+{
+ tBTA_HH_CMD_DATA *p_buf;
+ UINT16 len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) );
+
+ if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA));
+
+ p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
+ p_buf->hdr.layer_specific = (UINT16) dev_handle;
+ p_buf->t_type = t_type;
+ p_buf->data = data;
+ p_buf->param = param;
+ p_buf->p_data = p_data;
+ p_buf->rpt_id = rpt_id;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_HhSetReport
+**
+** Description send SET_REPORT to device.
+**
+** Parameter dev_handle: device handle
+** r_type: report type, could be BTA_HH_RPTT_OUTPUT or
+** BTA_HH_RPTT_FEATURE.
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, BT_HDR *p_data)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data);
+}
+/*******************************************************************************
+**
+** Function BTA_HhGetReport
+**
+** Description Send a GET_REPORT to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id, UINT16 buf_size)
+{
+ UINT8 param = (buf_size) ? (r_type | 0x08) : r_type;
+
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_REPORT, param,
+ buf_size, rpt_id, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhSetProtoMode
+**
+** Description This function set the protocol mode at specified HID handle
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSetProtoMode(UINT8 dev_handle, tBTA_HH_PROTO_MODE p_type)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_PROTOCOL, (UINT8)p_type,
+ 0, 0, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhGetProtoMode
+**
+** Description This function get protocol mode information.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetProtoMode(UINT8 dev_handle)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_PROTOCOL, 0, 0, 0, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhSetIdle
+**
+** Description send SET_IDLE to device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_IDLE, 0, idle_rate, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhGetIdle
+**
+** Description Send a GET_IDLE from HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetIdle(UINT8 dev_handle)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_IDLE, 0, 0, 0, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhSendCtrl
+**
+** Description Send a control command to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSendCtrl(UINT8 dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type)
+{
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (UINT8)c_type, 0, 0, NULL);
+}
+/*******************************************************************************
+**
+** Function BTA_HhSendData
+**
+** Description This function send DATA transaction to HID device.
+**
+** Parameter dev_handle: device handle
+** dev_bda: remote device address
+** p_data: data to be sent in the DATA transaction; or
+** the data to be write into the Output Report of a LE HID
+** device. The report is identified the report ID which is
+** the value of the byte (UINT8 *)(p_buf + 1) + p_buf->offset.
+** p_data->layer_specific needs to be set to the report type,
+** it can be OUTPUT report, or FEATURE report.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data)
+{
+ UNUSED(dev_bda);
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT)
+ {
+ APPL_TRACE_ERROR0("ERROR! Wrong report type! Write Command only valid for output report!");
+ return;
+ }
+#endif
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, 0, 0, p_data);
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhGetDscpInfo
+**
+** Description Get HID device report descriptor
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhGetDscpInfo(UINT8 dev_handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL)
+ {
+ memset(p_buf, 0, sizeof(BT_HDR));
+ p_buf->event = BTA_HH_API_GET_DSCP_EVT;
+ p_buf->layer_specific = (UINT16) dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_HhAddDev
+**
+** Description Add a virtually cabled device into HID-Host device list
+** to manage and assign a device handle for future API call,
+** host applciation call this API at start-up to initialize its
+** virtually cabled devices.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class,
+ UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info)
+{
+ tBTA_HH_MAINT_DEV *p_buf;
+ UINT16 len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;
+
+ p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len);
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV));
+
+ p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+ p_buf->sub_event = BTA_HH_ADD_DEV_EVT;
+ p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+
+ p_buf->attr_mask = (UINT16) attr_mask;
+ p_buf->sub_class = sub_class;
+ p_buf->app_id = app_id;
+ bdcpy(p_buf->bda, bda);
+
+ memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
+ if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list)
+ {
+ p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len;
+ p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1);
+ memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len);
+ }
+ else
+ {
+ p_buf->dscp_info.descriptor.dsc_list = NULL;
+ p_buf->dscp_info.descriptor.dl_len = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+/*******************************************************************************
+**
+** Function BTA_HhRemoveDev
+**
+** Description Remove a device from the HID host devices list.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhRemoveDev(UINT8 dev_handle )
+{
+ tBTA_HH_MAINT_DEV *p_buf;
+
+ p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf((UINT16)sizeof(tBTA_HH_MAINT_DEV));
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV));
+
+ p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+ p_buf->sub_event = BTA_HH_RMV_DEV_EVT;
+ p_buf->hdr.layer_specific = (UINT16) dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#if BTA_HH_LE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function BTA_HhUpdateLeScanParam
+**
+** Description Update the scan paramteters if connected to a LE hid device as
+** report host.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhUpdateLeScanParam(UINT8 dev_handle, UINT16 scan_int, UINT16 scan_win)
+{
+ tBTA_HH_SCPP_UPDATE *p_buf;
+
+ p_buf = (tBTA_HH_SCPP_UPDATE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_SCPP_UPDATE));
+
+ if (p_buf != NULL)
+ {
+ memset(p_buf, 0, sizeof(tBTA_HH_SCPP_UPDATE));
+
+ p_buf->hdr.event = BTA_HH_API_SCPP_UPDATE_EVT;
+ p_buf->hdr.layer_specific = (UINT16) dev_handle;
+ p_buf->scan_int = scan_int;
+ p_buf->scan_win = scan_win;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif
+/*******************************************************************************/
+/* Utility Function */
+/*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTA_HhParseBootRpt
+**
+** Description This utility function parse a boot mode report.
+** For keyboard report, report data will carry the keycode max
+** up to 6 key press in one report. Application need to convert
+** the keycode into keypress character according to keyboard
+** language.
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report,
+ UINT16 report_len)
+{
+ p_data->dev_type = BTA_HH_DEVT_UNKNOWN;
+
+ if (p_report)
+ {
+ /* first byte is report ID */
+ switch (p_report[0])
+ {
+ case BTA_HH_KEYBD_RPT_ID: /* key board report ID */
+ p_data->dev_type = p_report[0];
+ bta_hh_parse_keybd_rpt(p_data, p_report + 1, (UINT16)(report_len -1));
+ break;
+
+ case BTA_HH_MOUSE_RPT_ID: /* mouse report ID */
+ p_data->dev_type = p_report[0];
+ bta_hh_parse_mice_rpt(p_data, p_report + 1, (UINT16)(report_len - 1));
+ break;
+
+ default:
+ APPL_TRACE_DEBUG1("Unknown boot report: %d", p_report[0]);;
+ break;
+ }
+ }
+
+ return;
+}
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/bta/hd/bta_hd_int.h b/bta/hd/bta_hd_int.h
new file mode 100644
index 000000000..1ac40dac3
--- /dev/null
+++ b/bta/hd/bta_hd_int.h
@@ -0,0 +1,417 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains BTA HID Host internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef BTA_HH_INT_H
+#define BTA_HH_INT_H
+
+#include "bta_sys.h"
+#include "bd.h"
+#include "utl.h"
+#include "bta_hh_api.h"
+
+#if BTA_HH_LE_INCLUDED == TRUE
+#include "bta_gatt_api.h"
+#endif
+
+/* can be moved to bta_api.h */
+#define BTA_HH_MAX_RPT_CHARS 8
+
+#if (BTA_GATT_INCLUDED == FALSE || BLE_INCLUDED == FALSE)
+#undef BTA_HH_LE_INCLUDED
+#define BTA_HH_LE_INCLUDED FALSE
+#endif
+
+/* state machine events, these events are handled by the state machine */
+enum
+{
+ BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH),
+ BTA_HH_API_CLOSE_EVT,
+ BTA_HH_INT_OPEN_EVT,
+ BTA_HH_INT_CLOSE_EVT,
+ BTA_HH_INT_DATA_EVT,
+ BTA_HH_INT_CTRL_DATA,
+ BTA_HH_INT_HANDSK_EVT,
+ BTA_HH_SDP_CMPL_EVT,
+ BTA_HH_API_WRITE_DEV_EVT,
+ BTA_HH_API_GET_DSCP_EVT,
+ BTA_HH_API_MAINT_DEV_EVT,
+ BTA_HH_OPEN_CMPL_EVT,
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ BTA_HH_GATT_CLOSE_EVT,
+ BTA_HH_GATT_OPEN_EVT,
+ BTA_HH_START_ENC_EVT,
+ BTA_HH_ENC_CMPL_EVT,
+ BTA_HH_GATT_READ_CHAR_CMPL_EVT,
+ BTA_HH_GATT_WRITE_CHAR_CMPL_EVT,
+ BTA_HH_GATT_READ_DESCR_CMPL_EVT,
+ BTA_HH_GATT_WRITE_DESCR_CMPL_EVT,
+ BTA_HH_API_SCPP_UPDATE_EVT,
+ BTA_HH_GATT_ENC_CMPL_EVT,
+#endif
+
+ /* not handled by execute state machine */
+ BTA_HH_API_ENABLE_EVT,
+ BTA_HH_API_DISABLE_EVT,
+ BTA_HH_DISC_CMPL_EVT
+};
+typedef UINT16 tBTA_HH_INT_EVT; /* HID host internal events */
+
+#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1)
+
+/* event used to map between BTE event and BTA event */
+#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT
+#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT
+
+/* sub event code used for device maintainence API call */
+#define BTA_HH_ADD_DEV 0
+#define BTA_HH_REMOVE_DEV 1
+
+/* state machine states */
+enum
+{
+ BTA_HH_NULL_ST,
+ BTA_HH_IDLE_ST,
+ BTA_HH_W4_CONN_ST,
+ BTA_HH_CONN_ST
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ ,BTA_HH_W4_SEC
+#endif
+ ,BTA_HH_INVALID_ST /* Used to check invalid states before executing SM function */
+
+};
+typedef UINT8 tBTA_HH_STATE;
+
+/* data structure used to send a command/data to HID device */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 t_type;
+ UINT8 param;
+ UINT8 rpt_id;
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ UINT8 srvc_id;
+#endif
+ UINT16 data;
+ BT_HDR *p_data;
+}tBTA_HH_CMD_DATA;
+
+/* data type for BTA_HH_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT8 sec_mask;
+ UINT8 service_name[BTA_SERVICE_NAME_LEN+1];
+ tBTA_HH_CBACK *p_cback;
+} tBTA_HH_API_ENABLE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ UINT8 sec_mask;
+ tBTA_HH_PROTO_MODE mode;
+}tBTA_HH_API_CONN;
+
+/* internal event data from BTE HID callback */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR addr;
+ UINT32 data;
+ BT_HDR *p_data;
+}tBTA_HH_CBACK_DATA;
+
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bda;
+ UINT16 attr_mask;
+ UINT16 sub_event;
+ UINT8 sub_class;
+ UINT8 app_id;
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+}tBTA_HH_MAINT_DEV;
+
+#if BTA_HH_LE_INCLUDED == TRUE
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 conn_id;
+ tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect event is reported */
+
+}tBTA_HH_LE_CLOSE;
+
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 scan_int;
+ UINT16 scan_win;
+}tBTA_HH_SCPP_UPDATE;
+#endif
+/* union of all event data types */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_HH_API_ENABLE api_enable;
+ tBTA_HH_API_CONN api_conn;
+ tBTA_HH_CMD_DATA api_sndcmd;
+ tBTA_HH_CBACK_DATA hid_cback;
+ tBTA_HH_STATUS status;
+ tBTA_HH_MAINT_DEV api_maintdev;
+#if BTA_HH_LE_INCLUDED == TRUE
+ tBTA_HH_LE_CLOSE le_close;
+ tBTA_GATTC_OPEN le_open;
+ tBTA_HH_SCPP_UPDATE le_scpp_update;
+ tBTA_GATTC_ENC_CMPL_CB le_enc_cmpl;
+#endif
+} tBTA_HH_DATA;
+
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+typedef struct
+{
+ UINT8 index;
+ BOOLEAN in_use;
+ UINT8 inst_id; /* share service instance ID and report instance ID, as
+ hi 4 for service instance ID, low 4 as charatceristic instance ID */
+ tBTA_HH_RPT_TYPE rpt_type;
+ UINT16 uuid;
+ UINT16 prop;
+ UINT8 rpt_id;
+ BOOLEAN client_cfg_exist;
+ UINT16 client_cfg_value;
+}tBTA_HH_LE_RPT;
+
+#ifndef BTA_HH_LE_RPT_MAX
+#define BTA_HH_LE_RPT_MAX 20
+#endif
+
+typedef struct
+{
+ BOOLEAN in_use;
+ tBTA_HH_LE_RPT report[BTA_HH_LE_RPT_MAX];
+
+#define BTA_HH_LE_PROTO_MODE_BIT 0x01
+#define BTA_HH_LE_CP_BIT 0x02
+ UINT8 option_char; /* control point char exisit or not */
+
+ BOOLEAN expl_incl_srvc;
+ UINT8 incl_srvc_inst; /* assuming only one included service : battery service */
+ UINT8 cur_expl_char_idx; /* currently discovering service index */
+
+#define BTA_HH_LE_REMOTE_WAKE 0x01
+#define BTA_HH_LE_NORMAL_CONN 0x02
+ UINT8 flag; /* HID Information flag */
+ UINT8 *rpt_map;
+ UINT16 ext_rpt_ref;
+ tBTA_HH_DEV_DESCR descriptor;
+
+}tBTA_HH_LE_HID_SRVC;
+
+#ifndef BTA_HH_LE_HID_SRVC_MAX
+#define BTA_HH_LE_HID_SRVC_MAX 1
+#endif
+
+/* convert a HID handle to the LE CB index */
+#define BTA_HH_GET_LE_CB_IDX(x) (((x) >> 4) - 1)
+/* convert a GATT connection ID to HID device handle, it is the hi 4 bits of a UINT8 */
+#define BTA_HH_GET_LE_DEV_HDL(x) (UINT8)(((x) + 1) << 4)
+/* check to see if th edevice handle is a LE device handle */
+#define BTA_HH_IS_LE_DEV_HDL(x) ((x) & 0xf0)
+#define BTA_HH_IS_LE_DEV_HDL_VALID(x) (((x)>>4) < BTA_HH_LE_MAX_KNOWN)
+#endif
+
+/* device control block */
+typedef struct
+{
+ tBTA_HH_DEV_DSCP_INFO dscp_info; /* report descriptor and DI information */
+ BD_ADDR addr; /* BD-Addr of the HID device */
+ UINT16 attr_mask; /* attribute mask */
+ UINT16 w4_evt; /* W4_handshake event name */
+ UINT8 index; /* index number referenced to handle index */
+ UINT8 sub_class; /* Cod sub class */
+ UINT8 sec_mask; /* security mask */
+ UINT8 app_id; /* application ID for this connection */
+ UINT8 hid_handle; /* device handle : low 4 bits for regular HID: HID_HOST_MAX_DEVICES can not exceed 15;
+ high 4 bits for LE HID: GATT_MAX_PHY_CHANNEL can not exceed 15 */
+ BOOLEAN vp; /* virtually unplug flag */
+ BOOLEAN in_use; /* control block currently in use */
+ BOOLEAN incoming_conn; /* is incoming connection? */
+ UINT8 incoming_hid_handle; /* temporary handle for incoming connection? */
+ BOOLEAN opened; /* TRUE if device successfully opened HID connection */
+ tBTA_HH_PROTO_MODE mode; /* protocol mode */
+ tBTA_HH_STATE state; /* CB state */
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_DISC_NONE 0x00
+#define BTA_HH_LE_DISC_HIDS 0x01
+#define BTA_HH_LE_DISC_DIS 0x02
+#define BTA_HH_LE_DISC_SCPS 0x04
+
+ UINT8 disc_active;
+ tBTA_HH_STATUS status;
+ BOOLEAN is_le_device;
+ tBTA_HH_LE_HID_SRVC hid_srvc[BTA_HH_LE_HID_SRVC_MAX];
+ UINT16 conn_id;
+ BOOLEAN in_bg_conn;
+ UINT8 total_srvc;
+ UINT8 clt_cfg_idx;
+ UINT8 cur_srvc_index; /* currently discovering service index */
+ BOOLEAN scps_supported;
+
+#define BTA_HH_LE_SCPS_NOTIFY_NONE 0
+#define BTA_HH_LE_SCPS_NOTIFY_SPT 0x01
+#define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02
+ UINT8 scps_notify; /* scan refresh supported/notification enabled */
+#endif
+
+ BOOLEAN security_pending;
+} tBTA_HH_DEV_CB;
+
+/* key board parsing control block */
+typedef struct
+{
+ BOOLEAN mod_key[4]; /* ctrl, shift(upper), Alt, GUI */
+ BOOLEAN num_lock;
+ BOOLEAN caps_lock;
+ UINT8 last_report[BTA_HH_MAX_RPT_CHARS];
+} tBTA_HH_KB_CB;
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+typedef struct
+{
+ tBTA_HH_KB_CB kb_cb; /* key board control block,
+ suppose BTA will connect
+ to only one keyboard at
+ the same time */
+ tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */
+ tBTA_HH_DEV_CB* p_cur; /* current device control
+ block idx, used in sdp */
+ UINT8 cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index
+ map to dev handle */
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ UINT8 le_cb_index[BTA_HH_MAX_DEVICE]; /* maintain a CB index map to LE dev handle */
+ tBTA_GATTC_IF gatt_if;
+#endif
+ tBTA_HH_CBACK *p_cback; /* Application callbacks */
+ tSDP_DISCOVERY_DB* p_disc_db;
+ UINT8 trace_level; /* tracing level */
+ UINT8 cnt_num; /* connected device number */
+ BOOLEAN w4_disable; /* w4 disable flag */
+}
+tBTA_HH_CB;
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HH_CB bta_hh_cb;
+#else
+extern tBTA_HH_CB *bta_hh_cb_ptr;
+#define bta_hh_cb (*bta_hh_cb_ptr)
+#endif
+
+/* from bta_hh_cfg.c */
+extern tBTA_HH_CFG *p_bta_hh_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+extern BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg);
+extern void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event,
+ tBTA_HH_DATA *p_data);
+
+/* action functions */
+extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_close_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data);
+extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data);
+extern void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+
+/* utility functions */
+extern UINT8 bta_hh_find_cb(BD_ADDR bda);
+extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data,
+ UINT8 *p_report, UINT16 report_len);
+extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_kb_data,
+ UINT8 *p_report, UINT16 report_len);
+extern BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class);
+extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb);
+
+extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle,
+ UINT16 attr_mask,
+ tHID_DEV_DSCP_INFO *p_dscp_info,
+ UINT8 sub_class, UINT16 max_latency, UINT16 min_tout, UINT8 app_id);
+extern void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id,
+ UINT16 version, UINT8 flag);
+extern void bta_hh_cleanup_disable(tBTA_HH_STATUS status);
+
+extern UINT8 bta_hh_dev_handle_to_cb_idx(UINT8 dev_handle);
+
+/* action functions used outside state machine */
+extern void bta_hh_api_enable(tBTA_HH_DATA *p_data);
+extern void bta_hh_api_disable(void);
+extern void bta_hh_disc_cmpl(void);
+
+extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout);
+
+/* functions for LE HID */
+extern void bta_hh_le_enable(void);
+extern BOOLEAN bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if);
+extern void bta_hh_le_deregister(void);
+extern BOOLEAN bta_hh_is_le_device(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_open_conn(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB *p_cb);
+extern void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB *p_cb);
+extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info);
+extern void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB *p_cb);
+extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_gatt_open(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_gatt_close(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_start_srvc_discovery(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_w4_le_read_char_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_read_char_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_w4_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_w4_le_write_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_write_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_write_char_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+
+#if BTA_HH_DEBUG
+extern void bta_hh_trace_dev_db(void);
+#endif
+
+#endif
+
diff --git a/bta/hd/bta_hd_main.c b/bta/hd/bta_hd_main.c
new file mode 100644
index 000000000..c2554c1bb
--- /dev/null
+++ b/bta/hd/bta_hd_main.c
@@ -0,0 +1,587 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID host main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_HH_API_DISC_ACT, /* HID host process API close action */
+ BTA_HH_OPEN_ACT, /* HID host process BTA_HH_EVT_OPEN */
+ BTA_HH_CLOSE_ACT, /* HID host process BTA_HH_EVT_CLOSE */
+ BTA_HH_DATA_ACT, /* HID host receive data report */
+ BTA_HH_CTRL_DAT_ACT,
+ BTA_HH_HANDSK_ACT,
+ BTA_HH_START_SDP, /* HID host inquery */
+ BTA_HH_SDP_CMPL,
+ BTA_HH_WRITE_DEV_ACT,
+ BTA_HH_GET_DSCP_ACT,
+ BTA_HH_MAINT_DEV_ACT,
+ BTA_HH_OPEN_CMPL_ACT,
+ BTA_HH_OPEN_FAILURE,
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ BTA_HH_GATT_CLOSE,
+ BTA_HH_LE_OPEN_FAIL,
+ BTA_HH_GATT_OPEN,
+ BTA_HH_W4_LE_READ_CHAR,
+ BTA_HH_LE_READ_CHAR,
+ BTA_HH_W4_LE_READ_DESCR,
+ BTA_HH_LE_READ_DESCR,
+ BTA_HH_W4_LE_WRITE,
+ BTA_HH_LE_WRITE,
+ BTA_HH_WRITE_DESCR,
+ BTA_HH_START_SEC,
+ BTA_HH_SEC_CMPL,
+ BTA_HH_LE_UPDATE_SCPP,
+ BTA_HH_GATT_ENC_CMPL,
+#endif
+ BTA_HH_NUM_ACTIONS
+};
+
+#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+
+/* action functions */
+const tBTA_HH_ACTION bta_hh_action[] =
+{
+ bta_hh_api_disc_act,
+ bta_hh_open_act,
+ bta_hh_close_act,
+ bta_hh_data_act,
+ bta_hh_ctrl_dat_act,
+ bta_hh_handsk_act,
+ bta_hh_start_sdp,
+ bta_hh_sdp_cmpl,
+ bta_hh_write_dev_act,
+ bta_hh_get_dscp_act,
+ bta_hh_maint_dev_act,
+ bta_hh_open_cmpl_act,
+ bta_hh_open_failure
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ ,bta_hh_gatt_close
+ ,bta_hh_le_open_fail
+ ,bta_hh_gatt_open
+ ,bta_hh_w4_le_read_char_cmpl
+ ,bta_hh_le_read_char_cmpl
+ ,bta_hh_w4_le_read_descr_cmpl
+ ,bta_hh_le_read_descr_cmpl
+ ,bta_hh_w4_le_write_cmpl
+ ,bta_hh_le_write_cmpl
+ ,bta_hh_le_write_char_descr_cmpl
+ ,bta_hh_start_security
+ ,bta_hh_security_cmpl
+ ,bta_hh_le_update_scpp
+ ,bta_hh_le_notify_enc_cmpl
+#endif
+};
+
+/* state table information */
+#define BTA_HH_ACTION 0 /* position of action */
+#define BTA_HH_NEXT_STATE 1 /* position of next state */
+#define BTA_HH_NUM_COLS 2 /* number of columns */
+
+/* state table for idle state */
+const UINT8 bta_hh_st_idle[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST }
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST }
+/* BTA_HH_START_ENC_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* READ_CHAR_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* BTA_HH_GATT_WRITE_CMPL_EVT*/ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* READ_DESCR_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* SCPP_UPDATE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+#endif
+
+};
+
+
+const UINT8 bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST }
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST }
+/* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST }
+/* BTA_HH_START_ENC_EVT */ ,{BTA_HH_START_SEC, BTA_HH_W4_SEC }
+/* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }
+/* READ_CHAR_CMPL_EVT */ ,{BTA_HH_W4_LE_READ_CHAR, BTA_HH_W4_CONN_ST }
+/* BTA_HH_GATT_WRITE_CMPL_EVT*/ ,{BTA_HH_W4_LE_WRITE, BTA_HH_W4_CONN_ST }
+/* READ_DESCR_CMPL_EVT */ ,{BTA_HH_W4_LE_READ_DESCR, BTA_HH_W4_CONN_ST }
+/* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_WRITE_DESCR, BTA_HH_W4_CONN_ST }
+/* SCPP_UPDATE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }
+/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }
+#endif
+};
+
+
+const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_GATT_CLOSE, BTA_HH_IDLE_ST }
+/* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST }
+/* BTA_HH_START_ENC_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST }
+/* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST }
+/* READ_CHAR_CMPL_EVT */ ,{BTA_HH_LE_READ_CHAR, BTA_HH_CONN_ST }
+/* WRITE_CHAR_CMPL_EVT*/ ,{BTA_HH_LE_WRITE, BTA_HH_CONN_ST }
+/* READ_DESCR_CMPL_EVT */ ,{BTA_HH_LE_READ_DESCR, BTA_HH_CONN_ST } /* do not currently read any descr when connection up */
+/* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_WRITE_DESCR, BTA_HH_CONN_ST } /* do not currently write any descr when connection up */
+/* SCPP_UPDATE_EVT */ ,{BTA_HH_LE_UPDATE_SCPP, BTA_HH_CONN_ST }
+/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST }
+#endif
+};
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+const UINT8 bta_hh_st_w4_sec[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_W4_SEC },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE , BTA_HH_W4_SEC },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_W4_SEC },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_GATT_CLOSE_EVT */ {BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST },
+/* BTA_HH_GATT_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_START_ENC_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_ENC_CMPL_EVT */ {BTA_HH_SEC_CMPL, BTA_HH_W4_CONN_ST },
+/* READ_CHAR_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* BTA_HH_GATT_WRITE_CMPL_EVT*/ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* READ_DESCR_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC },
+/* WRITE_DESCR_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC }
+/* SCPP_UPDATE_EVT */ ,{BTA_HH_IGNORE, BTA_HH_W4_SEC }
+/* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_GATT_ENC_CMPL, BTA_HH_W4_SEC }
+};
+#endif
+
+/* type for state table */
+typedef const UINT8 (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS];
+
+/* state table */
+const tBTA_HH_ST_TBL bta_hh_st_tbl[] =
+{
+ bta_hh_st_idle,
+ bta_hh_st_w4_conn,
+ bta_hh_st_connected
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ ,bta_hh_st_w4_sec
+#endif
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HH_CB bta_hh_cb;
+#endif
+/*****************************************************************************
+** Static functions
+*****************************************************************************/
+#if BTA_HH_DEBUG == TRUE
+static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code);
+static char *bta_hh_state_code(tBTA_HH_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_hh_sm_execute
+**
+** Description State machine event handling function for HID Host
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
+{
+ tBTA_HH_ST_TBL state_table;
+ UINT8 action;
+ tBTA_HH cback_data;
+ tBTA_HH_EVT cback_event = 0;
+#if BTA_HH_DEBUG == TRUE
+ tBTA_HH_STATE in_state ;
+ UINT16 debug_event = event;
+#endif
+
+ memset(&cback_data, 0, sizeof(tBTA_HH));
+
+ /* handle exception, no valid control block was found */
+ if (!p_cb)
+ {
+ /* BTA HH enabled already? otherwise ignore the event although it's bad*/
+ if (bta_hh_cb.p_cback != NULL)
+ {
+ switch (event)
+ {
+ /* no control block available for new connection */
+ case BTA_HH_API_OPEN_EVT:
+ cback_event = BTA_HH_OPEN_EVT;
+ /* build cback data */
+ bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
+ cback_data.conn.status = BTA_HH_ERR_DB_FULL;
+ cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
+ break;
+ /* DB full, BTA_HhAddDev */
+ case BTA_HH_API_MAINT_DEV_EVT:
+ cback_event = p_data->api_maintdev.sub_event;
+
+ if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
+ {
+ bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
+ cback_data.dev_info.status = BTA_HH_ERR_DB_FULL;
+ cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE;
+ }
+ else
+ {
+ cback_data.dev_info.status = BTA_HH_ERR_HDL;
+ cback_data.dev_info.handle = (UINT8)p_data->api_maintdev.hdr.layer_specific;
+ }
+ break;
+ case BTA_HH_API_WRITE_DEV_EVT:
+ cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+ if (p_data->api_sndcmd.p_data != NULL)
+ {
+ GKI_freebuf(p_data->api_sndcmd.p_data);
+ }
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
+ {
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ }
+ else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
+ p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
+ {
+ cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ cback_data.hs_data.status = BTA_HH_ERR_HDL;
+ /* hs_data.rsp_data will be all zero, which is not valid value */
+ }
+ else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
+ p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ {
+ cback_data.status = BTA_HH_ERR_HDL;
+ cback_event = BTA_HH_VC_UNPLUG_EVT;
+ }
+ else
+ cback_event = 0;
+ break;
+
+ case BTA_HH_API_CLOSE_EVT:
+ cback_event = BTA_HH_CLOSE_EVT;
+
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ break;
+
+ default:
+ /* invalid handle, call bad API event */
+ APPL_TRACE_ERROR1("wrong device handle: [%d]", p_data->hdr.layer_specific);
+ break;
+ }
+ if (cback_event)
+ (* bta_hh_cb.p_cback)(cback_event, &cback_data);
+ }
+ }
+ /* corresponding CB is found, go to state machine */
+ else
+ {
+#if BTA_HH_DEBUG == TRUE
+ in_state = p_cb->state;
+ APPL_TRACE_EVENT3("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
+ in_state, bta_hh_state_code(in_state),
+ bta_hh_evt_code(debug_event));
+#endif
+
+ if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST))
+ {
+ APPL_TRACE_ERROR2("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
+ p_cb->state,event);
+ return;
+ }
+ state_table = bta_hh_st_tbl[p_cb->state - 1];
+
+ event &= 0xff;
+
+ p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;
+
+ if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
+ {
+ (*bta_hh_action[action])(p_cb, p_data);
+ }
+
+#if BTA_HH_DEBUG == TRUE
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_DEBUG3("HH State Change: [%s] -> [%s] after Event [%s]",
+ bta_hh_state_code(in_state),
+ bta_hh_state_code(p_cb->state),
+ bta_hh_evt_code(debug_event));
+ }
+#endif
+ }
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_hdl_event
+**
+** Description HID host main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
+{
+ UINT8 index = BTA_HH_IDX_INVALID;
+ tBTA_HH_DEV_CB *p_cb = NULL;
+
+ switch (p_msg->event)
+ {
+ case BTA_HH_API_ENABLE_EVT:
+ bta_hh_api_enable((tBTA_HH_DATA *) p_msg);
+ break;
+
+ case BTA_HH_API_DISABLE_EVT:
+ bta_hh_api_disable();
+ break;
+
+ case BTA_HH_DISC_CMPL_EVT: /* disable complete */
+ bta_hh_disc_cmpl();
+ break;
+
+ default:
+ /* all events processed in state machine need to find corresponding
+ CB before proceed */
+ if (p_msg->event == BTA_HH_API_OPEN_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
+ }
+ else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)
+ {
+ /* if add device */
+ if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);
+ }
+ else /* else remove device by handle */
+ {
+ index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
+// btla-specific ++
+ /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination
+ * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting
+ * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN.
+ * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
+ * force the index to be IDX_INVALID
+ */
+ if ((index != BTA_HH_IDX_INVALID) &&
+ (bta_hh_cb.kdev[index].in_use == FALSE)) {
+ index = BTA_HH_IDX_INVALID;
+ }
+// btla-specific --
+ }
+ }
+ else if (p_msg->event == BTA_HH_INT_OPEN_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
+ }
+ else
+ index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
+
+ if (index != BTA_HH_IDX_INVALID)
+ p_cb = &bta_hh_cb.kdev[index];
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
+#endif
+ bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);
+ }
+ return (TRUE);
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_HH_DEBUG
+/*******************************************************************************
+**
+** Function bta_hh_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_HH_API_DISABLE_EVT:
+ return "BTA_HH_API_DISABLE_EVT";
+ case BTA_HH_API_ENABLE_EVT:
+ return "BTA_HH_API_ENABLE_EVT";
+ case BTA_HH_API_OPEN_EVT:
+ return "BTA_HH_API_OPEN_EVT";
+ case BTA_HH_API_CLOSE_EVT:
+ return "BTA_HH_API_CLOSE_EVT";
+ case BTA_HH_INT_OPEN_EVT:
+ return "BTA_HH_INT_OPEN_EVT";
+ case BTA_HH_INT_CLOSE_EVT:
+ return "BTA_HH_INT_CLOSE_EVT";
+ case BTA_HH_INT_HANDSK_EVT:
+ return "BTA_HH_INT_HANDSK_EVT";
+ case BTA_HH_INT_DATA_EVT:
+ return "BTA_HH_INT_DATA_EVT";
+ case BTA_HH_INT_CTRL_DATA:
+ return "BTA_HH_INT_CTRL_DATA";
+ case BTA_HH_API_WRITE_DEV_EVT:
+ return "BTA_HH_API_WRITE_DEV_EVT";
+ case BTA_HH_SDP_CMPL_EVT:
+ return "BTA_HH_SDP_CMPL_EVT";
+ case BTA_HH_DISC_CMPL_EVT:
+ return "BTA_HH_DISC_CMPL_EVT";
+ case BTA_HH_API_MAINT_DEV_EVT:
+ return "BTA_HH_API_MAINT_DEV_EVT";
+ case BTA_HH_API_GET_DSCP_EVT:
+ return "BTA_HH_API_GET_DSCP_EVT";
+ case BTA_HH_OPEN_CMPL_EVT:
+ return "BTA_HH_OPEN_CMPL_EVT";
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ case BTA_HH_GATT_CLOSE_EVT:
+ return "BTA_HH_GATT_CLOSE_EVT";
+ case BTA_HH_GATT_OPEN_EVT:
+ return "BTA_HH_GATT_OPEN_EVT";
+ case BTA_HH_START_ENC_EVT:
+ return "BTA_HH_START_ENC_EVT";
+ case BTA_HH_ENC_CMPL_EVT:
+ return "BTA_HH_ENC_CMPL_EVT";
+ case BTA_HH_GATT_READ_CHAR_CMPL_EVT:
+ return "BTA_HH_GATT_READ_CHAR_CMPL_EVT";
+ case BTA_HH_GATT_WRITE_CHAR_CMPL_EVT:
+ return "BTA_HH_GATT_WRITE_CHAR_CMPL_EVT";
+ case BTA_HH_GATT_READ_DESCR_CMPL_EVT:
+ return "BTA_HH_GATT_READ_DESCR_CMPL_EVT";
+ case BTA_HH_GATT_WRITE_DESCR_CMPL_EVT:
+ return "BTA_HH_GATT_WRITE_DESCR_CMPL_EVT";
+#endif
+ default:
+ return "unknown HID Host event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_state_code
+**
+** Description get string representation of HID host state code.
+**
+** Returns void
+**
+*******************************************************************************/
+static char *bta_hh_state_code(tBTA_HH_STATE state_code)
+{
+ switch (state_code)
+ {
+ case BTA_HH_NULL_ST:
+ return"BTA_HH_NULL_ST";
+ case BTA_HH_IDLE_ST:
+ return "BTA_HH_IDLE_ST";
+ case BTA_HH_W4_CONN_ST:
+ return "BTA_HH_W4_CONN_ST";
+ case BTA_HH_CONN_ST:
+ return "BTA_HH_CONN_ST";
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ case BTA_HH_W4_SEC:
+ return "BTA_HH_W4_SEC";
+#endif
+ default:
+ return "unknown HID Host state";
+ }
+}
+
+#endif /* Debug Functions */
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/bta/include/bta_hd_api.h b/bta/include/bta_hd_api.h
new file mode 100644
index 000000000..893cac5cc
--- /dev/null
+++ b/bta/include/bta_hd_api.h
@@ -0,0 +1,558 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef BTA_HH_API_H
+#define BTA_HH_API_H
+
+#include "bta_api.h"
+#include "hidh_api.h"
+
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#endif
+
+/*****************************************************************************
+** Constants and Type Definitions
+*****************************************************************************/
+#ifndef BTA_HH_DEBUG
+#define BTA_HH_DEBUG TRUE
+#endif
+
+#ifndef BTA_HH_SSR_MAX_LATENCY_DEF
+#define BTA_HH_SSR_MAX_LATENCY_DEF 800 /* 500 ms*/
+#endif
+
+#ifndef BTA_HH_SSR_MIN_TOUT_DEF
+#define BTA_HH_SSR_MIN_TOUT_DEF 2
+#endif
+
+/* BTA HID Host callback events */
+#define BTA_HH_ENABLE_EVT 0 /* HH enabled */
+#define BTA_HH_DISABLE_EVT 1 /* HH disabled */
+#define BTA_HH_OPEN_EVT 2 /* connection opened */
+#define BTA_HH_CLOSE_EVT 3 /* connection closed */
+#define BTA_HH_GET_RPT_EVT 4 /* BTA_HhGetReport callback */
+#define BTA_HH_SET_RPT_EVT 5 /* BTA_HhSetReport callback */
+#define BTA_HH_GET_PROTO_EVT 6 /* BTA_GetProtoMode callback */
+#define BTA_HH_SET_PROTO_EVT 7 /* BTA_HhSetProtoMode callback */
+#define BTA_HH_GET_IDLE_EVT 8 /* BTA_HhGetIdle comes callback */
+#define BTA_HH_SET_IDLE_EVT 9 /* BTA_HhSetIdle finish callback */
+#define BTA_HH_GET_DSCP_EVT 10 /* Get report descriptor */
+#define BTA_HH_ADD_DEV_EVT 11 /* Add Device callback */
+#define BTA_HH_RMV_DEV_EVT 12 /* remove device finished */
+#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */
+#define BTA_HH_DATA_EVT 15
+#define BTA_HH_API_ERR_EVT 16 /* API error is caught */
+#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
+
+typedef UINT16 tBTA_HH_EVT;
+
+/* application ID(none-zero) for each type of device */
+#define BTA_HH_APP_ID_MI 1
+#define BTA_HH_APP_ID_KB 2
+#define BTA_HH_APP_ID_RMC 3
+#define BTA_HH_APP_ID_3DSG 4
+#define BTA_HH_APP_ID_JOY 5
+#define BTA_HH_APP_ID_GPAD 6
+#define BTA_HH_APP_ID_LE 0xff
+
+/* defined the minimum offset */
+#define BTA_HH_MIN_OFFSET L2CAP_MIN_OFFSET+1
+
+/* HID_HOST_MAX_DEVICES can not exceed 15 for th design of BTA HH */
+#define BTA_HH_IDX_INVALID 0xff
+#define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES
+
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* GATT_MAX_PHY_CHANNEL can not exceed 14 for the design of BTA HH */
+#define BTA_HH_LE_MAX_KNOWN GATT_MAX_PHY_CHANNEL
+#define BTA_HH_MAX_DEVICE (HID_HOST_MAX_DEVICES + GATT_MAX_PHY_CHANNEL)
+#else
+#define BTA_HH_MAX_DEVICE HID_HOST_MAX_DEVICES
+#endif
+/* invalid device handle */
+#define BTA_HH_INVALID_HANDLE 0xff
+
+/* type of protocol mode */
+#define BTA_HH_PROTO_RPT_MODE (0x00)
+#define BTA_HH_PROTO_BOOT_MODE (0x01)
+#define BTA_HH_PROTO_UNKNOWN (0xff)
+typedef UINT8 tBTA_HH_PROTO_MODE;
+
+enum
+{
+ BTA_HH_KEYBD_RPT_ID = 1,
+ BTA_HH_MOUSE_RPT_ID
+};
+typedef UINT8 tBTA_HH_BOOT_RPT_ID;
+
+/* type of devices, bit mask */
+#define BTA_HH_DEVT_UNKNOWN 0x00
+#define BTA_HH_DEVT_JOS 0x01 /* joy stick */
+#define BTA_HH_DEVT_GPD 0x02 /* game pad */
+#define BTA_HH_DEVT_RMC 0x03 /* remote control */
+#define BTA_HH_DEVT_SED 0x04 /* sensing device */
+#define BTA_HH_DEVT_DGT 0x05 /* Digitizer tablet */
+#define BTA_HH_DEVT_CDR 0x06 /* card reader */
+#define BTA_HH_DEVT_KBD 0x10 /* keyboard */
+#define BTA_HH_DEVT_MIC 0x20 /* pointing device */
+#define BTA_HH_DEVT_COM 0x30 /* Combo keyboard/pointing */
+#define BTA_HH_DEVT_OTHER 0x80
+typedef UINT8 tBTA_HH_DEVT;
+
+enum
+{
+ BTA_HH_OK,
+ BTA_HH_HS_HID_NOT_READY, /* handshake error : device not ready */
+ BTA_HH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */
+ BTA_HH_HS_TRANS_NOT_SPT, /* handshake error : transaction not spt */
+ BTA_HH_HS_INVALID_PARAM, /* handshake error : invalid paremter */
+ BTA_HH_HS_ERROR, /* handshake error : unspecified HS error */
+ BTA_HH_ERR, /* general BTA HH error */
+ BTA_HH_ERR_SDP, /* SDP error */
+ BTA_HH_ERR_PROTO, /* SET_Protocol error,
+ only used in BTA_HH_OPEN_EVT callback */
+
+ BTA_HH_ERR_DB_FULL, /* device database full error, used in
+ BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */
+ BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */
+ BTA_HH_ERR_NO_RES, /* out of system resources */
+ BTA_HH_ERR_AUTH_FAILED, /* authentication fail */
+ BTA_HH_ERR_HDL,
+ BTA_HH_ERR_SEC
+};
+typedef UINT8 tBTA_HH_STATUS;
+
+
+#define BTA_HH_VIRTUAL_CABLE HID_VIRTUAL_CABLE
+#define BTA_HH_NORMALLY_CONNECTABLE HID_NORMALLY_CONNECTABLE
+#define BTA_HH_RECONN_INIT HID_RECONN_INIT
+#define BTA_HH_SDP_DISABLE HID_SDP_DISABLE
+#define BTA_HH_BATTERY_POWER HID_BATTERY_POWER
+#define BTA_HH_REMOTE_WAKE HID_REMOTE_WAKE
+#define BTA_HH_SUP_TOUT_AVLBL HID_SUP_TOUT_AVLBL
+#define BTA_HH_SEC_REQUIRED HID_SEC_REQUIRED
+typedef UINT16 tBTA_HH_ATTR_MASK;
+
+/* supported type of device and corresponding application ID */
+typedef struct
+{
+ tBTA_HH_DEVT tod; /* type of device */
+ UINT8 app_id; /* corresponding application ID */
+}tBTA_HH_SPT_TOD;
+
+/* configuration struct */
+typedef struct
+{
+ UINT8 max_devt_spt; /* max number of types of devices spt */
+ tBTA_HH_SPT_TOD *p_devt_list; /* supported types of device list */
+ UINT16 sdp_db_size;
+}tBTA_HH_CFG;
+
+enum
+{
+ BTA_HH_RPTT_RESRV, /* reserved */
+ BTA_HH_RPTT_INPUT, /* input report */
+ BTA_HH_RPTT_OUTPUT, /* output report */
+ BTA_HH_RPTT_FEATURE /* feature report */
+};
+typedef UINT8 tBTA_HH_RPT_TYPE;
+
+/* HID_CONTROL operation code used in BTA_HhSendCtrl()
+*/
+enum
+{
+ BTA_HH_CTRL_NOP = 0 + HID_PAR_CONTROL_NOP ,/* mapping from BTE */
+ BTA_HH_CTRL_HARD_RESET, /* hard reset */
+ BTA_HH_CTRL_SOFT_RESET, /* soft reset */
+ BTA_HH_CTRL_SUSPEND, /* enter suspend */
+ BTA_HH_CTRL_EXIT_SUSPEND, /* exit suspend */
+ BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG /* virtual unplug */
+};
+typedef UINT8 tBTA_HH_TRANS_CTRL_TYPE;
+
+typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR;
+
+#define BTA_HH_SSR_PARAM_INVALID HID_SSR_PARAM_INVALID
+
+/* id DI is not existing in remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be set to 0xffff */
+#define BTA_HH_VENDOR_ID_INVALID 0xffff
+
+
+/* report descriptor information */
+typedef struct
+{
+ UINT16 vendor_id; /* vendor ID */
+ UINT16 product_id; /* product ID */
+ UINT16 version; /* version */
+ UINT16 ssr_max_latency; /* SSR max latency, BTA_HH_SSR_PARAM_INVALID if unknown */
+ UINT16 ssr_min_tout; /* SSR min timeout, BTA_HH_SSR_PARAM_INVALID if unknown */
+ UINT8 ctry_code; /*Country Code.*/
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_REMOTE_WAKE 0x01
+#define BTA_HH_LE_NORMAL_CONN 0x02
+
+ UINT8 flag;
+#endif
+ tBTA_HH_DEV_DESCR descriptor;
+}tBTA_HH_DEV_DSCP_INFO;
+
+/* callback event data for BTA_HH_OPEN_EVT */
+typedef struct
+{
+ BD_ADDR bda; /* HID device bd address */
+ tBTA_HH_STATUS status; /* operation status */
+ UINT8 handle; /* device handle */
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+ BOOLEAN le_hid; /* is LE devices? */
+ BOOLEAN scps_supported; /* scan parameter service supported */
+#endif
+
+} tBTA_HH_CONN;
+
+typedef tBTA_HH_CONN tBTA_HH_DEV_INFO;
+
+/* callback event data */
+typedef struct
+{
+ tBTA_HH_STATUS status; /* operation status */
+ UINT8 handle; /* device handle */
+} tBTA_HH_CBDATA;
+
+enum
+{
+ BTA_HH_MOD_CTRL_KEY,
+ BTA_HH_MOD_SHFT_KEY,
+ BTA_HH_MOD_ALT_KEY,
+ BTA_HH_MOD_GUI_KEY,
+ BTA_HH_MOD_MAX_KEY
+};
+
+/* parsed boot mode keyboard report */
+typedef struct
+{
+ UINT8 this_char[6]; /* virtual key code */
+ BOOLEAN mod_key[BTA_HH_MOD_MAX_KEY];
+ /* ctrl, shift, Alt, GUI */
+ /* modifier key: is Shift key pressed */
+ /* modifier key: is Ctrl key pressed */
+ /* modifier key: is Alt key pressed */
+ /* modifier key: GUI up/down */
+ BOOLEAN caps_lock; /* is caps locked */
+ BOOLEAN num_lock; /* is Num key pressed */
+} tBTA_HH_KEYBD_RPT;
+
+/* parsed boot mode mouse report */
+typedef struct
+{
+ UINT8 mouse_button; /* mouse button is clicked */
+ INT8 delta_x; /* displacement x */
+ INT8 delta_y; /* displacement y */
+}tBTA_HH_MICE_RPT;
+
+/* parsed Boot report */
+typedef struct
+{
+ tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */
+ union
+ {
+ tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
+ tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
+ } data_rpt;
+} tBTA_HH_BOOT_RPT;
+
+/* handshake data */
+typedef struct
+{
+ tBTA_HH_STATUS status; /* handshake status */
+ UINT8 handle; /* device handle */
+ union
+ {
+ tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
+ BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */
+ UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */
+ } rsp_data;
+
+}tBTA_HH_HSDATA;
+
+/* union of data associated with HD callback */
+typedef union
+{
+ tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */
+ tBTA_HH_CONN conn; /* BTA_HH_OPEN_EVT */
+ tBTA_HH_CBDATA dev_status; /* BTA_HH_CLOSE_EVT,
+ BTA_HH_SET_PROTO_EVT
+ BTA_HH_SET_RPT_EVT
+ BTA_HH_SET_IDLE_EVT
+ BTA_HH_UPDATE_SCPP_EVT */
+
+ tBTA_HH_STATUS status; /* BTA_HH_ENABLE_EVT */
+ tBTA_HH_DEV_DSCP_INFO dscp_info; /* BTA_HH_GET_DSCP_EVT */
+ tBTA_HH_HSDATA hs_data; /* GET_ transaction callback
+ BTA_HH_GET_RPT_EVT
+ BTA_HH_GET_PROTO_EVT
+ BTA_HH_GET_IDLE_EVT */
+} tBTA_HH;
+
+/* BTA HH callback function */
+typedef void (tBTA_HH_CBACK) (tBTA_HH_EVT event, tBTA_HH *p_data);
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function BTA_HhRegister
+**
+** Description This function enable HID host and registers HID-Host with
+** lower layers.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_HhDeregister
+**
+** Description This function is called when the host is about power down.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_HhOpen
+**
+** Description This function is called to start an inquiry and read SDP
+** record of responding devices; connect to a device if only
+** one active HID device is found.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhOpen (BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode,
+ tBTA_SEC sec_mask);
+
+/*******************************************************************************
+**
+** Function BTA_HhClose
+**
+** Description This function disconnects the device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhClose(UINT8 dev_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HhSetProtoMode
+**
+** Description This function set the protocol mode at specified HID handle
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSetProtoMode(UINT8 handle, tBTA_HH_PROTO_MODE t_type);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetProtoMode
+**
+** Description This function get the protocol mode of a specified HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetProtoMode(UINT8 dev_handle);
+/*******************************************************************************
+**
+** Function BTA_HhSetReport
+**
+** Description send SET_REPORT to device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type,
+ BT_HDR *p_data);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetReport
+**
+** Description Send a GET_REPORT to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type,
+ UINT8 rpt_id, UINT16 buf_size);
+/*******************************************************************************
+**
+** Function BTA_HhSetIdle
+**
+** Description send SET_IDLE to device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetIdle
+**
+** Description Send a GET_IDLE to HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetIdle(UINT8 dev_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HhSendCtrl
+**
+** Description Send HID_CONTROL request to a HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSendCtrl(UINT8 dev_handle,
+ tBTA_HH_TRANS_CTRL_TYPE c_type);
+
+/*******************************************************************************
+**
+** Function BTA_HhSetIdle
+**
+** Description send SET_IDLE to device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate);
+
+
+/*******************************************************************************
+**
+** Function BTA_HhGetIdle
+**
+** Description Send a GET_IDLE from HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetIdle(UINT8 dev_handle);
+
+/*******************************************************************************
+**
+** Function BTA_HhSendData
+**
+** Description Send DATA transaction to a HID device.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function BTA_HhGetDscpInfo
+**
+** Description Get report descriptor of the device
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhGetDscpInfo(UINT8 dev_handle);
+
+/*******************************************************************************
+** Function BTA_HhAddDev
+**
+** Description Add a virtually cabled device into HID-Host device list
+** to manage and assign a device handle for future API call,
+** host applciation call this API at start-up to initialize its
+** virtually cabled devices.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask,
+ UINT8 sub_class, UINT8 app_id,
+ tBTA_HH_DEV_DSCP_INFO dscp_info);
+/*******************************************************************************
+**
+** Function BTA_HhRemoveDev
+**
+** Description Remove a device from the HID host devices list.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhRemoveDev(UINT8 dev_handle );
+
+/*******************************************************************************
+**
+** Parsing Utility Functions
+**
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function BTA_HhParseBootRpt
+**
+** Description This utility function parse a boot mode report.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report,
+ UINT16 report_len);
+
+#if BTA_HH_LE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function BTA_HhUpdateLeScanParam
+**
+** Description Update the scan paramteters if connected to a LE hid device as
+** report host.
+**
+** Returns void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhUpdateLeScanParam(UINT8 dev_handle, UINT16 scan_int, UINT16 scan_win);
+#endif
+/* test commands */
+BTA_API extern void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HH_API_H */
diff --git a/btif/include/btif_hd.h b/btif/include/btif_hd.h
new file mode 100644
index 000000000..d864ec43e
--- /dev/null
+++ b/btif/include/btif_hd.h
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HH_H
+#define BTIF_HH_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+#include <stdint.h>
+#include "bta_hh_api.h"
+#include "btu.h"
+
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define BTIF_HH_MAX_HID 8
+#define BTIF_HH_MAX_ADDED_DEV 32
+
+#define BTIF_HH_MAX_KEYSTATES 3
+#define BTIF_HH_KEYSTATE_MASK_NUMLOCK 0x01
+#define BTIF_HH_KEYSTATE_MASK_CAPSLOCK 0x02
+#define BTIF_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
+
+
+/*******************************************************************************
+** Type definitions and return values
+********************************************************************************/
+
+typedef enum
+{
+ BTIF_HH_DISABLED = 0,
+ BTIF_HH_ENABLED,
+ BTIF_HH_DISABLING,
+ BTIF_HH_DEV_UNKNOWN,
+ BTIF_HH_DEV_CONNECTING,
+ BTIF_HH_DEV_CONNECTED,
+ BTIF_HH_DEV_DISCONNECTED
+} BTIF_HH_STATUS;
+
+typedef struct
+{
+ bthh_connection_state_t dev_status;
+ UINT8 dev_handle;
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_ATTR_MASK attr_mask;
+ UINT8 sub_class;
+ UINT8 app_id;
+ int fd;
+ BT_HDR *p_buf;
+ UINT32 hh_poll_thread_id;
+ UINT8 hh_keep_polling;
+ BOOLEAN vup_timer_active;
+ TIMER_LIST_ENT vup_timer;
+ BOOLEAN local_vup; // Indicated locally initiated VUP
+} btif_hh_device_t;
+
+/* Control block to maintain properties of devices */
+typedef struct
+{
+ UINT8 dev_handle;
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_ATTR_MASK attr_mask;
+} btif_hh_added_device_t;
+
+/**
+ * BTIF-HH control block to maintain added devices and currently
+ * connected hid devices
+ */
+typedef struct
+{
+ BTIF_HH_STATUS status;
+ btif_hh_device_t devices[BTIF_HH_MAX_HID];
+ UINT32 device_num;
+ btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
+ btif_hh_device_t *p_curr_dev;
+} btif_hh_cb_t;
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+extern btif_hh_cb_t btif_hh_cb;
+
+extern btif_hh_device_t *btif_hh_find_connected_dev_by_handle(UINT8 handle);
+extern void btif_hh_remove_device(bt_bdaddr_t bd_addr);
+BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask);
+extern bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t *bd_addr);
+extern void btif_hh_disconnect(bt_bdaddr_t *bd_addr);
+extern void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type,
+ UINT16 size, UINT8* report);
+
+BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
+
+#endif
diff --git a/btif/src/btif_hd.c b/btif/src/btif_hd.c
new file mode 100644
index 000000000..e1b2f6906
--- /dev/null
+++ b/btif/src/btif_hd.c
@@ -0,0 +1,1820 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hh.c
+ *
+ * Description: HID Host Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#define LOG_TAG "BTIF_HH"
+
+#include "bta_api.h"
+#include "bta_hh_api.h"
+#include "bd.h"
+#include "btif_storage.h"
+
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_hh.h"
+#include "gki.h"
+#include "l2c_api.h"
+
+
+#define BTIF_HH_APP_ID_MI 0x01
+#define BTIF_HH_APP_ID_KB 0x02
+
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+#define COD_HID_MAJOR 0x0500
+
+#define KEYSTATE_FILEPATH "/data/misc/bluedroid/bt_hh_ks" //keep this in sync with HID host jni
+
+#define HID_REPORT_CAPSLOCK 0x39
+#define HID_REPORT_NUMLOCK 0x53
+#define HID_REPORT_SCROLLLOCK 0x47
+
+//For Apple Magic Mouse
+#define MAGICMOUSE_VENDOR_ID 0x05ac
+#define MAGICMOUSE_PRODUCT_ID 0x030d
+
+#define LOGITECH_KB_MX5500_VENDOR_ID 0x046D
+#define LOGITECH_KB_MX5500_PRODUCT_ID 0xB30B
+
+extern const int BT_UID;
+extern const int BT_GID;
+static int btif_hh_prev_keyevents=0; //The previous key events
+static int btif_hh_keylockstates=0; //The current key state of each key
+
+#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)
+#endif
+
+#ifndef BTUI_HH_MOUSE_SECURITY
+#define BTUI_HH_MOUSE_SECURITY (BTA_SEC_NONE)
+#endif
+
+/* HH request events */
+typedef enum
+{
+ BTIF_HH_CONNECT_REQ_EVT = 0,
+ BTIF_HH_DISCONNECT_REQ_EVT,
+ BTIF_HH_VUP_REQ_EVT
+} btif_hh_req_evt_t;
+
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+#define BTIF_HH_SERVICES (BTA_HID_SERVICE_MASK)
+
+
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+typedef struct hid_kb_list
+{
+ UINT16 product_id;
+ UINT16 version_id;
+ char* kb_name;
+} tHID_KB_LIST;
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+btif_hh_cb_t btif_hh_cb;
+
+static bthh_callbacks_t *bt_hh_callbacks = NULL;
+
+/* List of HID keyboards for which the NUMLOCK state needs to be
+ * turned ON by default. Add devices to this list to apply the
+ * NUMLOCK state toggle on fpr first connect.*/
+static tHID_KB_LIST hid_kb_numlock_on_list[] =
+{
+ {LOGITECH_KB_MX5500_PRODUCT_ID,
+ LOGITECH_KB_MX5500_VENDOR_ID,
+ "Logitech MX5500 Keyboard"}
+};
+
+
+#define CHECK_BTHH_INIT() if (bt_hh_callbacks == NULL)\
+ {\
+ BTIF_TRACE_WARNING1("BTHH: %s: BTHH not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else\
+ {\
+ BTIF_TRACE_EVENT1("BTHH: %s", __FUNCTION__);\
+ }
+
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+extern void bta_hh_co_destroy(int fd);
+extern void bta_hh_co_write(int fd, UINT8* rpt, UINT16 len);
+extern bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr);
+extern void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id,
+ UINT16 product_id, UINT16 version, UINT8 ctry_code,
+ int dscp_len, UINT8 *p_dscp);
+extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
+extern void btif_dm_cb_remove_bond(bt_bdaddr_t *bd_addr);
+extern BOOLEAN check_cod_hid(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
+extern int scru_ascii_2_hex(char *p_ascii, int len, UINT8 *p_hex);
+extern void btif_dm_hh_open_failed(bt_bdaddr_t *bdaddr);
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+static void set_keylockstate(int keymask, BOOLEAN isSet);
+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);
+
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+static int get_keylockstates()
+{
+ return btif_hh_keylockstates;
+}
+
+static void set_keylockstate(int keymask, BOOLEAN isSet)
+{
+ if(isSet)
+ btif_hh_keylockstates |= keymask;
+}
+
+/*******************************************************************************
+**
+** Function toggle_os_keylockstates
+**
+** Description Function to toggle the keyboard lock states managed by the linux.
+** This function is used in by two call paths
+** (1) if the lock state change occurred from an onscreen keyboard,
+** this function is called to update the lock state maintained
+ for the HID keyboard(s)
+** (2) if a HID keyboard is disconnected and reconnected,
+** this function is called to update the lock state maintained
+ for the HID keyboard(s)
+** Returns void
+*******************************************************************************/
+
+static void toggle_os_keylockstates(int fd, int changedlockstates)
+{
+ BTIF_TRACE_EVENT3("%s: fd = %d, changedlockstates = 0x%x",
+ __FUNCTION__, fd, changedlockstates);
+ UINT8 hidreport[9];
+ int reportIndex;
+ memset(hidreport,0,9);
+ hidreport[0]=1;
+ reportIndex=4;
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_CAPSLOCK) {
+ BTIF_TRACE_DEBUG1("%s Setting CAPSLOCK", __FUNCTION__);
+ hidreport[reportIndex++] = (UINT8)HID_REPORT_CAPSLOCK;
+ }
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_NUMLOCK) {
+ BTIF_TRACE_DEBUG1("%s Setting NUMLOCK", __FUNCTION__);
+ hidreport[reportIndex++] = (UINT8)HID_REPORT_NUMLOCK;
+ }
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_SCROLLLOCK) {
+ BTIF_TRACE_DEBUG1("%s Setting SCROLLLOCK", __FUNCTION__);
+ hidreport[reportIndex++] = (UINT8) HID_REPORT_SCROLLLOCK;
+ }
+
+ BTIF_TRACE_DEBUG4("Writing hidreport #1 to os: "\
+ "%s: %x %x %x", __FUNCTION__,
+ hidreport[0], hidreport[1], hidreport[2]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x", __FUNCTION__,
+ hidreport[3], hidreport[4], hidreport[5]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x", __FUNCTION__,
+ hidreport[6], hidreport[7], hidreport[8]);
+ bta_hh_co_write(fd , hidreport, sizeof(hidreport));
+ usleep(200000);
+ memset(hidreport,0,9);
+ hidreport[0]=1;
+ BTIF_TRACE_DEBUG4("Writing hidreport #2 to os: "\
+ "%s: %x %x %x", __FUNCTION__,
+ hidreport[0], hidreport[1], hidreport[2]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x", __FUNCTION__,
+ hidreport[3], hidreport[4], hidreport[5]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x ", __FUNCTION__,
+ hidreport[6], hidreport[7], hidreport[8]);
+ bta_hh_co_write(fd , hidreport, sizeof(hidreport));
+}
+
+/*******************************************************************************
+**
+** Function update_keyboard_lockstates
+**
+** Description Sends a report to the keyboard to set the lock states of keys
+**
+*******************************************************************************/
+static void update_keyboard_lockstates(btif_hh_device_t *p_dev)
+{
+ UINT8 len = 2; /* reportid + 1 byte report*/
+ BD_ADDR* bda;
+
+ /* Set report for other keyboards */
+ BTIF_TRACE_EVENT3("%s: setting report on dev_handle %d to 0x%x",
+ __FUNCTION__, p_dev->dev_handle, btif_hh_keylockstates);
+
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ /* Get SetReport buffer */
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET +
+ sizeof(BT_HDR)));
+ if (p_dev->p_buf != NULL) {
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+ p_dev->p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
+
+ /* LED status updated by data event */
+ UINT8 *pbuf_data = (UINT8 *)(p_dev->p_buf + 1)
+ + p_dev->p_buf->offset;
+ pbuf_data[0]=0x01; /*report id */
+ pbuf_data[1]=btif_hh_keylockstates; /*keystate*/
+ bda = (BD_ADDR*) (&p_dev->bd_addr);
+ BTA_HhSendData(p_dev->dev_handle, *bda,
+ p_dev->p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function sync_lockstate_on_connect
+**
+** Description Function to update the keyboard lock states managed by the OS
+** when a HID keyboard is connected or disconnected and reconnected
+** Returns void
+*******************************************************************************/
+static void sync_lockstate_on_connect(btif_hh_device_t *p_dev)
+{
+ int keylockstates;
+
+ BTIF_TRACE_EVENT1("%s: Syncing keyboard lock states after "\
+ "reconnect...",__FUNCTION__);
+ /*If the device is connected, update keyboard state */
+ update_keyboard_lockstates(p_dev);
+
+ /*Check if the lockstate of caps,scroll,num is set.
+ If so, send a report to the kernel
+ so the lockstate is in sync */
+ keylockstates = get_keylockstates();
+ if (keylockstates)
+ {
+ BTIF_TRACE_DEBUG2("%s: Sending hid report to kernel "\
+ "indicating lock key state 0x%x",__FUNCTION__,
+ keylockstates);
+ usleep(200000);
+ toggle_os_keylockstates(p_dev->fd, keylockstates);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG2("%s: NOT sending hid report to kernel "\
+ "indicating lock key state 0x%x",__FUNCTION__,
+ keylockstates);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_find_dev_by_handle
+**
+** Description Return the device pointer of the specified device handle
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+static btif_hh_device_t *btif_hh_find_dev_by_handle(UINT8 handle)
+{
+ UINT32 i;
+ // LOGV("%s: handle = %d", __FUNCTION__, handle);
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ btif_hh_cb.devices[i].dev_handle == handle)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hh_find_connected_dev_by_handle
+**
+** Description Return the connected device pointer of the specified device handle
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+btif_hh_device_t *btif_hh_find_connected_dev_by_handle(UINT8 handle)
+{
+ UINT32 i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+ btif_hh_cb.devices[i].dev_handle == handle)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_find_dev_by_bda
+**
+** Description Return the device pointer of the specified bt_bdaddr_t.
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+static btif_hh_device_t *btif_hh_find_dev_by_bda(bt_bdaddr_t *bd_addr)
+{
+ UINT32 i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_find_connected_dev_by_bda
+**
+** Description Return the connected device pointer of the specified bt_bdaddr_t.
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+static btif_hh_device_t *btif_hh_find_connected_dev_by_bda(bt_bdaddr_t *bd_addr)
+{
+ UINT32 i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+ memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+** Returns TRUE if add successfully, otherwise FALSE.
+*******************************************************************************/
+BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask)
+{
+ int i;
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN) == 0) {
+ BTIF_TRACE_WARNING6(" Device %02X:%02X:%02X:%02X:%02X:%02X already added",
+ bda.address[0], bda.address[1], bda.address[2], bda.address[3], bda.address[4], bda.address[5]);
+ return FALSE;
+ }
+ }
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (btif_hh_cb.added_devices[i].bd_addr.address[0] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[1] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[2] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[3] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[4] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[5] == 0)
+ {
+ BTIF_TRACE_WARNING6(" Added device %02X:%02X:%02X:%02X:%02X:%02X",
+ bda.address[0], bda.address[1], bda.address[2], bda.address[3], bda.address[4], bda.address[5]);
+ memcpy(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN);
+ btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+ btif_hh_cb.added_devices[i].attr_mask = attr_mask;
+ return TRUE;
+ }
+ }
+
+ BTIF_TRACE_WARNING1("%s: Error, out of space to add device",__FUNCTION__);
+ return FALSE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_hh_remove_device
+ **
+ ** Description Remove an added device from the stack.
+ **
+ ** Returns void
+ *******************************************************************************/
+void btif_hh_remove_device(bt_bdaddr_t bd_addr)
+{
+ int i;
+ btif_hh_device_t *p_dev;
+ btif_hh_added_device_t *p_added_dev;
+
+ ALOGI("%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __FUNCTION__,
+ bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ p_added_dev = &btif_hh_cb.added_devices[i];
+ if (memcmp(&(p_added_dev->bd_addr),&bd_addr, 6) == 0) {
+ BTA_HhRemoveDev(p_added_dev->dev_handle);
+ btif_storage_remove_hid_info(&(p_added_dev->bd_addr));
+ memset(&(p_added_dev->bd_addr), 0, 6);
+ p_added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ break;
+ }
+ }
+
+ p_dev = btif_hh_find_dev_by_bda(&bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING6(" Oops, can't find device [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+ return;
+ }
+
+ /* need to notify up-layer device is disconnected to avoid state out of sync with up-layer */
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr), BTHH_CONN_STATE_DISCONNECTED);
+
+ p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN;
+ p_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ if (btif_hh_cb.device_num > 0) {
+ btif_hh_cb.device_num--;
+ }
+ else {
+ BTIF_TRACE_WARNING1("%s: device_num = 0", __FUNCTION__);
+ }
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ p_dev->p_buf = NULL;
+ }
+
+ p_dev->hh_keep_polling = 0;
+ p_dev->hh_poll_thread_id = -1;
+ BTIF_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ if (p_dev->fd >= 0) {
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+}
+
+
+BOOLEAN btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest , tBTA_HH_DEV_DSCP_INFO* src)
+{
+ dest->descriptor.dl_len = 0;
+ if (src->descriptor.dl_len >0)
+ {
+ dest->descriptor.dsc_list = (UINT8 *) GKI_getbuf(src->descriptor.dl_len);
+ if (dest->descriptor.dsc_list == NULL)
+ {
+ BTIF_TRACE_WARNING1("%s: Failed to allocate DSCP for CB", __FUNCTION__);
+ return FALSE;
+ }
+ }
+ memcpy(dest->descriptor.dsc_list, src->descriptor.dsc_list, src->descriptor.dl_len);
+ dest->descriptor.dl_len = src->descriptor.dl_len;
+ dest->vendor_id = src->vendor_id;
+ dest->product_id = src->product_id;
+ dest->version = src->version;
+ dest->ctry_code = src->ctry_code;
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hh_virtual_unplug
+**
+** Description Virtual unplug initiated from the BTIF thread context
+** Special handling for HID mouse-
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t *bd_addr)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ btif_hh_device_t *p_dev;
+ char bd_str[18];
+ sprintf(bd_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3],
+ bd_addr->address[4], bd_addr->address[5]);
+ p_dev = btif_hh_find_dev_by_bda(bd_addr);
+ if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED)
+ && (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);
+ p_dev->local_vup = TRUE;
+ BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ BTIF_TRACE_ERROR2("%s: Error, device %s not opened.", __FUNCTION__, bd_str);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_connect
+**
+** Description connection initiated from the BTIF thread context
+**
+** Returns int status
+**
+*******************************************************************************/
+
+bt_status_t btif_hh_connect(bt_bdaddr_t *bd_addr)
+{
+ btif_hh_device_t *dev;
+ btif_hh_added_device_t *added_dev = NULL;
+ char bda_str[20];
+ int i;
+ BD_ADDR *bda = (BD_ADDR*)bd_addr;
+ tBTA_HH_CONN conn;
+ CHECK_BTHH_INIT();
+ dev = btif_hh_find_dev_by_bda(bd_addr);
+ BTIF_TRACE_DEBUG0("Connect _hh");
+ sprintf(bda_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ if (dev == NULL && btif_hh_cb.device_num >= BTIF_HH_MAX_HID) {
+ // No space for more HID device now.
+ BTIF_TRACE_WARNING2("%s: Error, exceeded the maximum supported HID device number %d",
+ __FUNCTION__, BTIF_HH_MAX_HID);
+ return BT_STATUS_FAIL;
+ }
+
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0) {
+ added_dev = &btif_hh_cb.added_devices[i];
+ BTIF_TRACE_WARNING3("%s: Device %s already added, attr_mask = 0x%x",
+ __FUNCTION__, bda_str, added_dev->attr_mask);
+ }
+ }
+
+ if (added_dev != NULL) {
+ if (added_dev->dev_handle == BTA_HH_INVALID_HANDLE) {
+ // No space for more HID device now.
+ BTIF_TRACE_ERROR2("%s: Error, device %s added but addition failed", __FUNCTION__, bda_str);
+ memset(&(added_dev->bd_addr), 0, 6);
+ added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ return BT_STATUS_FAIL;
+ }
+ }
+
+ if (added_dev == NULL ||
+ (added_dev->attr_mask & HID_NORMALLY_CONNECTABLE) != 0 ||
+ (added_dev->attr_mask & HID_RECONN_INIT) == 0)
+ {
+ tBTA_SEC sec_mask = BTUI_HH_SECURITY;
+ btif_hh_cb.status = BTIF_HH_DEV_CONNECTING;
+ BD_ADDR *bda = (BD_ADDR*)bd_addr;
+ BTA_HhOpen(*bda, BTA_HH_PROTO_RPT_MODE, sec_mask);
+ }
+ else
+ {
+ // This device shall be connected from the host side.
+ BTIF_TRACE_ERROR2("%s: Error, device %s can only be reconnected from device side",
+ __FUNCTION__, bda_str);
+ return BT_STATUS_FAIL;
+ }
+
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr, BTHH_CONN_STATE_CONNECTING);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_disconnect
+**
+** Description disconnection initiated from the BTIF thread context
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_hh_disconnect(bt_bdaddr_t *bd_addr)
+{
+ BD_ADDR *bda = (BD_ADDR*)bd_addr;
+ btif_hh_device_t *p_dev;
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL)
+ {
+ BTA_HhClose(p_dev->dev_handle);
+ }
+ else
+ BTIF_TRACE_DEBUG1("%s-- Error: device not connected:",__FUNCTION__);
+}
+
+/*******************************************************************************
+**
+** Function btif_btif_hh_setreport
+**
+** Description setreport initiated from the BTIF thread context
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type, UINT16 size,
+ UINT8* report)
+{
+ UINT8 hexbuf[20];
+ UINT16 len = size;
+ int i = 0;
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR)));
+ if (p_dev->p_buf == NULL) {
+ APPL_TRACE_ERROR2("%s: Error, failed to allocate RPT buffer, len = %d", __FUNCTION__, len);
+ return;
+ }
+
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ //Build a SetReport data buffer
+ memset(hexbuf, 0, 20);
+ for(i=0; i<len; i++)
+ hexbuf[i] = report[i];
+
+ UINT8* pbuf_data;
+ pbuf_data = (UINT8*) (p_dev->p_buf + 1) + p_dev->p_buf->offset;
+ memcpy(pbuf_data, hexbuf, len);
+ BTA_HhSetReport(p_dev->dev_handle, r_type, p_dev->p_buf);
+
+}
+
+/*****************************************************************************
+** Section name (Group of functions)
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** btif hh api functions (no context switch)
+**
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_hh_upstreams_evt
+**
+** Description Executes HH UPSTREAMS events in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hh_upstreams_evt(UINT16 event, char* p_param)
+{
+ tBTA_HH *p_data = (tBTA_HH *)p_param;
+ bdstr_t bdstr;
+ btif_hh_device_t *p_dev = NULL;
+ int i;
+ int len, tmplen;
+
+ BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hh_event(event));
+
+ switch (event)
+ {
+ case BTA_HH_ENABLE_EVT:
+ BTIF_TRACE_DEBUG2("%s: BTA_HH_ENABLE_EVT: status =%d",__FUNCTION__, p_data->status);
+ if (p_data->status == BTA_HH_OK) {
+ btif_hh_cb.status = BTIF_HH_ENABLED;
+ BTIF_TRACE_DEBUG1("%s--Loading added devices",__FUNCTION__);
+ /* Add hid descriptors for already bonded hid devices*/
+ btif_storage_load_bonded_hid_info();
+ }
+ else {
+ btif_hh_cb.status = BTIF_HH_DISABLED;
+ BTIF_TRACE_WARNING1("BTA_HH_ENABLE_EVT: Error, HH enabling failed, status = %d", p_data->status);
+ }
+ break;
+
+ case BTA_HH_DISABLE_EVT:
+ btif_hh_cb.status = BTIF_HH_DISABLED;
+ if (p_data->status == BTA_HH_OK) {
+ int i;
+ //Clear the control block
+ memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+ for (i = 0; i < BTIF_HH_MAX_HID; i++){
+ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+ }
+ }
+ else
+ BTIF_TRACE_WARNING1("BTA_HH_DISABLE_EVT: Error, HH disabling failed, status = %d", p_data->status);
+ break;
+
+ case BTA_HH_OPEN_EVT:
+ BTIF_TRACE_WARNING3("%s: BTA_HH_OPN_EVT: handle=%d, status =%d",__FUNCTION__, p_data->conn.handle, p_data->conn.status);
+ if (p_data->conn.status == BTA_HH_OK) {
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING1("BTA_HH_OPEN_EVT: Error, cannot find device with handle %d", p_data->conn.handle);
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ // The connect request must come from device side and exceeded the connected
+ // HID device number.
+ BTA_HhClose(p_data->conn.handle);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, (bt_bdaddr_t*) &p_data->conn.bda,BTHH_CONN_STATE_DISCONNECTED);
+ }
+ else if (p_dev->fd < 0) {
+ BTIF_TRACE_WARNING0("BTA_HH_OPEN_EVT: Error, failed to find the uhid driver...");
+ memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+ //remove the connection and then try again to reconnect from the mouse side to recover
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ BTA_HhClose(p_data->conn.handle);
+ }
+ else {
+ BTIF_TRACE_WARNING1("BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle ... %d",p_data->conn.handle);
+ memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+ btif_hh_cb.status = BTIF_HH_DEV_CONNECTED;
+ // Send set_idle if the peer_device is a keyboard
+ if (check_cod((bt_bdaddr_t*)p_data->conn.bda, COD_HID_KEYBOARD )||
+ check_cod((bt_bdaddr_t*)p_data->conn.bda, COD_HID_COMBO))
+ BTA_HhSetIdle(p_data->conn.handle, 0);
+ btif_hh_cb.p_curr_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ BTA_HhGetDscpInfo(p_data->conn.handle);
+ p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);
+ }
+ }
+ else {
+ bt_bdaddr_t *bdaddr = (bt_bdaddr_t*)p_data->conn.bda;
+ btif_dm_hh_open_failed(bdaddr);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, (bt_bdaddr_t*) &p_data->conn.bda,BTHH_CONN_STATE_DISCONNECTED);
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ }
+ break;
+ case BTA_HH_CLOSE_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_CLOSE_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev != NULL) {
+ BTIF_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ 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);
+ BTIF_TRACE_DEBUG2("%s: Closing uhid fd = %d", __FUNCTION__, p_dev->fd);
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+ else {
+ BTIF_TRACE_WARNING1("Error: cannot find device with handle %d", p_data->dev_status.handle);
+ }
+ break;
+ case BTA_HH_GET_RPT_EVT: {
+ BT_HDR *hdr = p_data->hs_data.rsp_data.p_rpt_data;
+ UINT8 *data = NULL;
+ UINT16 len = 0;
+
+ BTIF_TRACE_DEBUG2("BTA_HH_GET_RPT_EVT: status = %d, handle = %d",
+ p_data->hs_data.status, p_data->hs_data.handle);
+ /* p_rpt_data in HANDSHAKE response case */
+ if (hdr) {
+ data = (UINT8 *)(hdr + 1) + hdr->offset;
+ len = hdr->len;
+ }
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
+ if (p_dev) {
+ HAL_CBACK(bt_hh_callbacks, get_report_cb,
+ (bt_bdaddr_t*) &(p_dev->bd_addr),
+ (bthh_status_t) p_data->hs_data.status, data, len);
+ } else {
+ BTIF_TRACE_WARNING1("Error: cannot find device with handle %d", p_data->hs_data.handle);
+ }
+ break;
+ }
+ case BTA_HH_SET_RPT_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_SET_RPT_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev != NULL && p_dev->p_buf != NULL) {
+ BTIF_TRACE_DEBUG0("Freeing buffer..." );
+ GKI_freebuf(p_dev->p_buf);
+ p_dev->p_buf = NULL;
+ }
+ break;
+
+ case BTA_HH_GET_PROTO_EVT:
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ BTIF_TRACE_WARNING4("BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s",
+ p_data->hs_data.status, p_data->hs_data.handle,
+ p_data->hs_data.rsp_data.proto_mode,
+ (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE) ? "Report Mode" :
+ (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_BOOT_MODE) ? "Boot Mode" : "Unsupported");
+ HAL_CBACK(bt_hh_callbacks, protocol_mode_cb,(bt_bdaddr_t*) &(p_dev->bd_addr), (bthh_status_t)p_data->hs_data.status,
+ (bthh_protocol_mode_t) p_data->hs_data.rsp_data.proto_mode);
+ break;
+
+ case BTA_HH_SET_PROTO_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_SET_PROTO_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ break;
+
+ case BTA_HH_GET_IDLE_EVT:
+ BTIF_TRACE_DEBUG3("BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d",
+ p_data->hs_data.handle, p_data->hs_data.status,
+ p_data->hs_data.rsp_data.idle_rate);
+ break;
+
+ case BTA_HH_SET_IDLE_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_SET_IDLE_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ break;
+
+ case BTA_HH_GET_DSCP_EVT:
+ BTIF_TRACE_WARNING2("BTA_HH_GET_DSCP_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ len = p_data->dscp_info.descriptor.dl_len;
+ BTIF_TRACE_DEBUG1("BTA_HH_GET_DSCP_EVT: len = %d", len);
+ p_dev = btif_hh_cb.p_curr_dev;
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR0("BTA_HH_GET_DSCP_EVT: No HID device is currently connected");
+ return;
+ }
+ if (p_dev->fd < 0) {
+ ALOGE("BTA_HH_GET_DSCP_EVT: Error, failed to find the uhid driver...");
+ return;
+ }
+ {
+ char *cached_name = NULL;
+ bt_bdname_t bdname;
+ bt_property_t prop_name;
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(
+ &p_dev->bd_addr, &prop_name) == BT_STATUS_SUCCESS)
+ {
+ cached_name = (char *)bdname.name;
+ }
+ else
+ {
+ cached_name = "Bluetooth HID";
+ }
+
+ BTIF_TRACE_WARNING2("%s: name = %s", __FUNCTION__, cached_name);
+ bta_hh_co_send_hid_info(p_dev, cached_name,
+ p_data->dscp_info.vendor_id, p_data->dscp_info.product_id,
+ p_data->dscp_info.version, p_data->dscp_info.ctry_code,
+ len, p_data->dscp_info.descriptor.dsc_list);
+ if (btif_hh_add_added_dev(p_dev->bd_addr, p_dev->attr_mask)) {
+ BD_ADDR bda;
+ bdcpy(bda, p_dev->bd_addr.address);
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ bt_status_t ret;
+ 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]);
+ 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,
+ p_data->dscp_info.vendor_id, p_data->dscp_info.product_id,
+ p_data->dscp_info.version, p_data->dscp_info.ctry_code,
+ len, p_data->dscp_info.descriptor.dsc_list);
+
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret);
+ BTIF_TRACE_WARNING0("BTA_HH_GET_DSCP_EVT: Called add device");
+
+ //Free buffer created for dscp_info;
+ if (dscp_info.descriptor.dl_len >0 && dscp_info.descriptor.dsc_list != NULL)
+ {
+ GKI_freebuf(dscp_info.descriptor.dsc_list);
+ dscp_info.descriptor.dsc_list = NULL;
+ dscp_info.descriptor.dl_len=0;
+ }
+ }
+ else {
+ //Device already added.
+ BTIF_TRACE_WARNING1("%s: Device already added ",__FUNCTION__);
+ }
+ /*Sync HID Keyboard lockstates */
+ tmplen = sizeof(hid_kb_numlock_on_list)
+ / sizeof(tHID_KB_LIST);
+ for(i = 0; i< tmplen; i++)
+ {
+ if(p_data->dscp_info.vendor_id
+ == hid_kb_numlock_on_list[i].version_id &&
+ p_data->dscp_info.product_id
+ == hid_kb_numlock_on_list[i].product_id)
+ {
+ BTIF_TRACE_DEBUG3("%s() idx[%d] Enabling "\
+ "NUMLOCK for device :: %s", __FUNCTION__,
+ i, hid_kb_numlock_on_list[i].kb_name);
+ /* Enable NUMLOCK by default so that numeric
+ keys work from first keyboard connect */
+ set_keylockstate(BTIF_HH_KEYSTATE_MASK_NUMLOCK,
+ TRUE);
+ sync_lockstate_on_connect(p_dev);
+ /* End Sync HID Keyboard lockstates */
+ break;
+ }
+ }
+ }
+ break;
+
+ case BTA_HH_ADD_DEV_EVT:
+ BTIF_TRACE_WARNING2("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",p_data->dev_info.status, p_data->dev_info.handle);
+ int i;
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address, p_data->dev_info.bda, 6) == 0) {
+ if (p_data->dev_info.status == BTA_HH_OK) {
+ btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;
+ }
+ else {
+ memset(btif_hh_cb.added_devices[i].bd_addr.address, 0, 6);
+ btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+ }
+ break;
+ }
+ }
+ break;
+ case BTA_HH_RMV_DEV_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d",
+ p_data->dev_info.status, p_data->dev_info.handle);
+ BTIF_TRACE_DEBUG6("BTA_HH_RMV_DEV_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_data->dev_info.bda[0], p_data->dev_info.bda[1], p_data->dev_info.bda[2],
+ p_data->dev_info.bda[3], p_data->dev_info.bda[4], p_data->dev_info.bda[5]);
+ break;
+
+
+ case BTA_HH_VC_UNPLUG_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ 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]);
+ /* 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 bond", __FUNCTION__);
+ /* If it is locally initiated VUP or remote device has its major COD as
+ Peripheral removed the bond.*/
+ if (p_dev->local_vup || check_cod_hid(&(p_dev->bd_addr), COD_HID_MAJOR))
+ {
+ p_dev->local_vup = FALSE;
+ BTA_DmRemoveDevice((UINT8 *)p_dev->bd_addr.address);
+ }
+ else
+ btif_hh_remove_device(p_dev->bd_addr);
+ HAL_CBACK(bt_hh_callbacks, virtual_unplug_cb,&(p_dev->bd_addr),
+ p_data->dev_status.status);
+ }
+ break;
+
+ case BTA_HH_API_ERR_EVT :
+ ALOGI("BTA_HH API_ERR");
+ break;
+
+
+
+ default:
+ BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bte_hh_evt
+**
+** Description Switches context from BTE to BTIF for all HH events
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH *p_data)
+{
+ bt_status_t status;
+ int param_len = 0;
+
+ if (BTA_HH_ENABLE_EVT == event)
+ param_len = sizeof(tBTA_HH_STATUS);
+ else if (BTA_HH_OPEN_EVT == event)
+ param_len = sizeof(tBTA_HH_CONN);
+ else if (BTA_HH_DISABLE_EVT == event)
+ param_len = sizeof(tBTA_HH_STATUS);
+ else if (BTA_HH_CLOSE_EVT == event)
+ param_len = sizeof(tBTA_HH_CBDATA);
+ else if (BTA_HH_GET_DSCP_EVT == event)
+ param_len = sizeof(tBTA_HH_DEV_DSCP_INFO);
+ else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event)|| (BTA_HH_GET_IDLE_EVT == event))
+ param_len = sizeof(tBTA_HH_HSDATA);
+ else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) || (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event))
+ param_len = sizeof(tBTA_HH_CBDATA);
+ else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event) )
+ param_len = sizeof(tBTA_HH_DEV_INFO);
+ else if (BTA_HH_API_ERR_EVT == event)
+ param_len = 0;
+ /* switch context to btif task context (copy full union size for convenience) */
+ status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_handle_evt
+**
+** Description Switches context for immediate callback
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_hh_handle_evt(UINT16 event, char *p_param)
+{
+ bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)p_param;
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ int ret;
+ switch(event)
+ {
+ case BTIF_HH_CONNECT_REQ_EVT:
+ {
+ ret = btif_hh_connect(bd_addr);
+ if(ret == BT_STATUS_SUCCESS)
+ {
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,bd_addr,BTHH_CONN_STATE_CONNECTING);
+ }
+ else
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,bd_addr,BTHH_CONN_STATE_DISCONNECTED);
+ }
+ break;
+
+ case BTIF_HH_DISCONNECT_REQ_EVT:
+ {
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ btif_hh_disconnect(bd_addr);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,bd_addr,BTHH_CONN_STATE_DISCONNECTING);
+ }
+ break;
+
+ case BTIF_HH_VUP_REQ_EVT:
+ {
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ ret = btif_hh_virtual_unplug(bd_addr);
+ }
+ break;
+
+ default:
+ {
+ BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** 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);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_init
+**
+** Description initializes the hh interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthh_callbacks_t* callbacks )
+{
+ UINT32 i;
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ bt_hh_callbacks = callbacks;
+ memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+ for (i = 0; i < BTIF_HH_MAX_HID; i++){
+ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+ }
+ /* Invoke the enable service API to the core to set the appropriate service_id */
+ btif_enable_service(BTA_HID_SERVICE_ID);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function connect
+**
+** Description connect to hid device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect( bt_bdaddr_t *bd_addr)
+{
+ if(btif_hh_cb.status != BTIF_HH_DEV_CONNECTING)
+ {
+ btif_transfer_context(btif_hh_handle_evt, BTIF_HH_CONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ return BT_STATUS_BUSY;
+}
+
+/*******************************************************************************
+**
+** Function disconnect
+**
+** Description disconnect from hid device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_WARNING2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL)
+ {
+ return btif_transfer_context(btif_hh_handle_evt, BTIF_HH_DISCONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ }
+ else
+ {
+ BTIF_TRACE_WARNING1("%s: Error, device not opened.", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function virtual_unplug
+**
+** Description Virtual UnPlug (VUP) the specified HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t virtual_unplug (bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ char bd_str[18];
+ sprintf(bd_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3],
+ bd_addr->address[4], bd_addr->address[5]);
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+ p_dev = btif_hh_find_dev_by_bda(bd_addr);
+ if (!p_dev)
+ {
+ BTIF_TRACE_ERROR2("%s: Error, device %s not opened.", __FUNCTION__, bd_str);
+ return BT_STATUS_FAIL;
+ }
+ btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function set_info
+**
+** Description Set the HID device descriptor for the specified HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_info (bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info )
+{
+ CHECK_BTHH_INIT();
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ BTIF_TRACE_DEBUG6("%s: sub_class = 0x%02x, app_id = %d, vendor_id = 0x%04x, "
+ "product_id = 0x%04x, version= 0x%04x",
+ __FUNCTION__, hid_info.sub_class,
+ hid_info.app_id, hid_info.vendor_id, hid_info.product_id,
+ hid_info.version);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ dscp_info.vendor_id = hid_info.vendor_id;
+ dscp_info.product_id = hid_info.product_id;
+ dscp_info.version = hid_info.version;
+ dscp_info.ctry_code = hid_info.ctry_code;
+
+ dscp_info.descriptor.dl_len = hid_info.dl_len;
+ dscp_info.descriptor.dsc_list = (UINT8 *) GKI_getbuf(dscp_info.descriptor.dl_len);
+ if (dscp_info.descriptor.dsc_list == NULL)
+ {
+ ALOGE("%s: Failed to allocate DSCP for CB", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ memcpy(dscp_info.descriptor.dsc_list, &(hid_info.dsc_list), hid_info.dl_len);
+
+ if (btif_hh_add_added_dev(*bd_addr, hid_info.attr_mask))
+ {
+ BTA_HhAddDev(*bda, hid_info.attr_mask, hid_info.sub_class,
+ hid_info.app_id, dscp_info);
+ }
+
+ GKI_freebuf(dscp_info.descriptor.dsc_list);
+
+ return BT_STATUS_SUCCESS;
+}
+/*******************************************************************************
+**
+** Function get_idle_time
+**
+** Description Get the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_idle_time(bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6(" addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ //BTA_HhGetIdle(p_dev->dev_handle);
+ }
+ else {
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_idle_time
+**
+** Description Set the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_idle_time (bt_bdaddr_t *bd_addr, uint8_t idle_time)
+{
+ UNUSED(idle_time);
+
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ //BTA_HhSetIdle(p_dev->dev_handle, idle_time);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function get_protocol
+**
+** Description Get the HID proto mode.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_protocol (bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+ UNUSED(protocolMode);
+
+ BTIF_TRACE_DEBUG6(" addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+
+ BTA_HhGetProtoMode(p_dev->dev_handle);
+ }
+ else {
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_protocol
+**
+** Description Set the HID proto mode.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_protocol (bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ UINT8 proto_mode = protocolMode;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG2("%s:proto_mode = %d", __FUNCTION__,protocolMode);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else if (protocolMode != BTA_HH_PROTO_RPT_MODE && protocolMode != BTA_HH_PROTO_BOOT_MODE) {
+ BTIF_TRACE_WARNING2("s: Error, device proto_mode = %d.", __FUNCTION__, proto_mode);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ BTA_HhSetProtoMode(p_dev->dev_handle, protocolMode);
+ }
+
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function get_report
+**
+** Description Send a GET_REPORT to HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_report (bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, uint8_t reportId, int bufferSize)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG4("%s:proto_mode = %dr_type = %d, rpt_id = %d, buf_size = %d", __FUNCTION__,
+ reportType, reportId, bufferSize);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR6("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else if ( ((int) reportType) <= BTA_HH_RPTT_RESRV || ((int) reportType) > BTA_HH_RPTT_FEATURE) {
+ BTIF_TRACE_ERROR6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ BTA_HhGetReport(p_dev->dev_handle, reportType,
+ reportId, bufferSize);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_report
+**
+** Description Send a SET_REPORT to HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_report (bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, char* report)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG2("%s:reportType = %d", __FUNCTION__,reportType);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR6("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else if ( ( (int) reportType) <= BTA_HH_RPTT_RESRV || ( (int) reportType) > BTA_HH_RPTT_FEATURE) {
+ BTIF_TRACE_ERROR6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ int hex_bytes_filled;
+ UINT8 hexbuf[200];
+ UINT16 len = (strlen(report) + 1) / 2;
+
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR)));
+ if (p_dev->p_buf == NULL) {
+ BTIF_TRACE_ERROR2("%s: Error, failed to allocate RPT buffer, len = %d", __FUNCTION__, len);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ /* Build a SetReport data buffer */
+ memset(hexbuf, 0, 200);
+ //TODO
+ hex_bytes_filled = ascii_2_hex(report, len, hexbuf);
+ ALOGI("Hex bytes filled, hex value: %d", hex_bytes_filled);
+ if (hex_bytes_filled) {
+ UINT8* pbuf_data;
+ pbuf_data = (UINT8*) (p_dev->p_buf + 1) + p_dev->p_buf->offset;
+ memcpy(pbuf_data, hexbuf, hex_bytes_filled);
+ BTA_HhSetReport(p_dev->dev_handle, reportType, p_dev->p_buf);
+ }
+ return BT_STATUS_SUCCESS;
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function send_data
+**
+** Description Send a SEND_DATA to HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t send_data (bt_bdaddr_t *bd_addr, char* data)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR6("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+
+ else {
+ int hex_bytes_filled;
+ UINT8 hexbuf[200];
+ UINT16 len = (strlen(data) + 1) / 2;
+
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR)));
+ if (p_dev->p_buf == NULL) {
+ BTIF_TRACE_ERROR2("%s: Error, failed to allocate RPT buffer, len = %d", __FUNCTION__, len);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ /* Build a SetReport data buffer */
+ memset(hexbuf, 0, 200);
+ hex_bytes_filled = ascii_2_hex(data, len, hexbuf);
+ BTIF_TRACE_ERROR2("Hex bytes filled, hex value: %d, %d", hex_bytes_filled, len);
+
+ if (hex_bytes_filled) {
+ UINT8* pbuf_data;
+ pbuf_data = (UINT8*) (p_dev->p_buf + 1) + p_dev->p_buf->offset;
+ memcpy(pbuf_data, hexbuf, hex_bytes_filled);
+ p_dev->p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
+ BTA_HhSendData(p_dev->dev_handle, *bda, p_dev->p_buf);
+ return BT_STATUS_SUCCESS;
+ }
+
+ }
+ return BT_STATUS_FAIL;
+}
+
+
+/*******************************************************************************
+**
+** Function cleanup
+**
+** Description Closes the HH interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static void cleanup( void )
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ btif_hh_device_t *p_dev;
+ int i;
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_WARNING2("%s: HH disabling or disabled already, status = %d", __FUNCTION__, btif_hh_cb.status);
+ return;
+ }
+ btif_hh_cb.status = BTIF_HH_DISABLING;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->fd >= 0) {
+ BTIF_TRACE_DEBUG2("%s: Closing uhid fd = %d", __FUNCTION__, p_dev->fd);
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ p_dev->hh_keep_polling = 0;
+ p_dev->hh_poll_thread_id = -1;
+ }
+ }
+
+ if (bt_hh_callbacks)
+ {
+ btif_disable_service(BTA_HID_SERVICE_ID);
+ bt_hh_callbacks = NULL;
+ }
+
+}
+
+static const bthh_interface_t bthhInterface = {
+ sizeof(bthhInterface),
+ init,
+ connect,
+ disconnect,
+ virtual_unplug,
+ set_info,
+ get_protocol,
+ set_protocol,
+// get_idle_time,
+// set_idle_time,
+ get_report,
+ set_report,
+ send_data,
+ cleanup,
+};
+
+/*******************************************************************************
+**
+** Function btif_hh_execute_service
+**
+** Description Initializes/Shuts down the service
+**
+** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_hh_execute_service(BOOLEAN b_enable)
+{
+ if (b_enable)
+ {
+ /* Enable and register with BTA-HH */
+ BTA_HhEnable(BTA_SEC_NONE, bte_hh_evt);
+ }
+ else {
+ /* Disable HH */
+ BTA_HhDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_get_interface
+**
+** Description Get the hh callback interface
+**
+** Returns bthh_interface_t
+**
+*******************************************************************************/
+const bthh_interface_t *btif_hh_get_interface()
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bthhInterface;
+}
diff --git a/stack/hid/hidd_api.c b/stack/hid/hidd_api.c
new file mode 100644
index 000000000..1868671f9
--- /dev/null
+++ b/stack/hid/hidd_api.c
@@ -0,0 +1,599 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID HOST API entry points
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hiddefs.h"
+#include "hidh_api.h"
+#include "hidh_int.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "btm_int.h"
+
+#if HID_DYNAMIC_MEMORY == FALSE
+tHID_HOST_CTB hh_cb;
+#endif
+
+static void hidh_search_callback (UINT16 sdp_result);
+
+/*******************************************************************************
+**
+** Function HID_HostGetSDPRecord
+**
+** Description This function reads the device SDP record
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostGetSDPRecord ( BD_ADDR addr, tSDP_DISCOVERY_DB *p_db, UINT32 db_len,
+ tHID_HOST_SDP_CALLBACK *sdp_cback )
+{
+ tSDP_UUID uuid_list;
+
+ if( hh_cb.sdp_busy )
+ return HID_ERR_SDP_BUSY;
+
+ uuid_list.len = 2;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+ hh_cb.p_sdp_db = p_db;
+ SDP_InitDiscoveryDb (p_db, db_len, 1, &uuid_list, 0, NULL);
+
+ if (SDP_ServiceSearchRequest (addr, p_db, hidh_search_callback))
+ {
+ hh_cb.sdp_cback = sdp_cback ;
+ hh_cb.sdp_busy = TRUE;
+ return HID_SUCCESS;
+ }
+ else
+ return HID_ERR_NO_RESOURCES;
+}
+
+void hidh_get_str_attr( tSDP_DISC_REC *p_rec, UINT16 attr_id, UINT16 max_len, char *str )
+{
+ tSDP_DISC_ATTR *p_attr;
+ UINT16 name_len;
+
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, attr_id)) != NULL)
+ {
+ if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len )
+ {
+ memcpy( str, (char *) p_attr->attr_value.v.array, name_len );
+ str[name_len] = '\0';
+ }
+ else
+ {
+ memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 );
+ str[max_len-1] = '\0';
+ }
+ }
+ else
+ str[0] = '\0';
+}
+
+
+static void hidh_search_callback (UINT16 sdp_result)
+{
+ tSDP_DISCOVERY_DB *p_db = hh_cb.p_sdp_db;
+ tSDP_DISC_REC *p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
+ tBT_UUID hid_uuid;
+ tHID_DEV_SDP_INFO *p_nvi = &hh_cb.sdp_rec;
+ UINT16 attr_mask = 0;
+
+ hid_uuid.len = LEN_UUID_16;
+ hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+ hh_cb.sdp_busy = FALSE;
+
+ if (sdp_result != SDP_SUCCESS)
+ {
+ hh_cb.sdp_cback(sdp_result, 0, NULL);
+ return;
+ }
+
+ if ((p_rec = SDP_FindServiceUUIDInDb (p_db, &hid_uuid, NULL)) == NULL)
+ {
+ hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
+ return;
+ }
+
+ memset (&hh_cb.sdp_rec, 0, sizeof( tHID_DEV_SDP_INFO ));
+
+ /* First, verify the mandatory fields we care about */
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL)
+ || (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ || ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL)
+ || (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ || ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL)
+ || ((p_repdesc = p_subattr2->p_next_attr) == NULL)
+ || (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE))
+ {
+ hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
+ return;
+ }
+
+ if ((p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type)) != 0)
+ p_nvi->dscp_info.dsc_list = (UINT8 *) &p_repdesc->attr_value;
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) &&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_VIRTUAL_CABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_RECONN_INIT;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_NORMALLY_CONNECTABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL)&&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_SDP_DISABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL)&&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_BATTERY_POWER;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL)&&
+ (p_attr->attr_value.v.u8) )
+ {
+ attr_mask |= HID_REMOTE_WAKE;
+ }
+
+ hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN, p_nvi->svc_name );
+ hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN, p_nvi->svc_descr );
+ hidh_get_str_attr( p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN, p_nvi->prov_name );
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL))
+ {
+ p_nvi->rel_num = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL))
+ {
+ p_nvi->ctry_code = p_attr->attr_value.v.u8;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL))
+ {
+ p_nvi->sub_class = p_attr->attr_value.v.u8;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL))
+ {
+ p_nvi->hpars_ver = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL))
+ {
+ attr_mask |= HID_SUP_TOUT_AVLBL;
+ p_nvi->sup_timeout = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL))
+ {
+ attr_mask |= HID_SSR_MAX_LATENCY;
+ p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
+ }
+ else
+ p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
+
+ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL))
+ {
+ attr_mask |= HID_SSR_MIN_TOUT;
+ p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
+ }
+ else
+ p_nvi->ssr_min_tout = HID_SSR_PARAM_INVALID;
+
+ hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
+ hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
+}
+
+
+/*******************************************************************************
+**
+** Function HID_HostInit
+**
+** Description This function initializes the control block and trace variable
+**
+** Returns void
+**
+*******************************************************************************/
+void HID_HostInit (void)
+{
+ memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
+
+#if defined(HID_INITIAL_TRACE_LEVEL)
+ hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
+#else
+ hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function HID_HostSetTraceLevel
+**
+** Description This function sets the trace level for HID Host. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 HID_HostSetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ hh_cb.trace_level = new_level;
+
+ return (hh_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function HID_HostRegister
+**
+** Description This function registers HID-Host with lower layers
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback)
+{
+ tHID_STATUS st;
+
+ if( hh_cb.reg_flag )
+ return HID_ERR_ALREADY_REGISTERED;
+
+ if( dev_cback == NULL )
+ return HID_ERR_INVALID_PARAM;
+
+ /* Register with L2CAP */
+ if( (st = hidh_conn_reg()) != HID_SUCCESS )
+ {
+ return st;
+ }
+
+ hh_cb.callback = dev_cback ;
+ hh_cb.reg_flag = TRUE;
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function HID_HostDeregister
+**
+** Description This function is called when the host is about power down.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostDeregister(void)
+{
+ UINT8 i;
+
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ for( i=0; i<HID_HOST_MAX_DEVICES; i++ )
+ {
+ HID_HostRemoveDev( i ) ;
+ }
+
+ hidh_conn_dereg();
+ hh_cb.reg_flag = FALSE;
+
+ return (HID_SUCCESS) ;
+}
+
+/*******************************************************************************
+**
+** Function HID_HostAddDev
+**
+** Description This is called so HID-host may manage this device.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle )
+{
+ int i;
+ /* Find an entry for this device in hh_cb.devices array */
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ for( i=0; i<HID_HOST_MAX_DEVICES; i++)
+ {
+ if((hh_cb.devices[i].in_use) &&
+ (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN)))
+ break;
+ }
+
+ if (i== HID_HOST_MAX_DEVICES )
+ {
+ for( i=0; i<HID_HOST_MAX_DEVICES; i++)
+ {
+ if( !hh_cb.devices[i].in_use)
+ break;
+ }
+ }
+
+ if( i==HID_HOST_MAX_DEVICES )
+ return HID_ERR_NO_RESOURCES;
+
+ if (!hh_cb.devices[i].in_use)
+ {
+ hh_cb.devices[i].in_use = TRUE;
+ memcpy( hh_cb.devices[i].addr, addr, sizeof( BD_ADDR ) ) ;
+ hh_cb.devices[i].state = HID_DEV_NO_CONN;
+ hh_cb.devices[i].conn_tries = 0 ;
+ }
+
+ if (attr_mask != HID_ATTR_MASK_IGNORE)
+ hh_cb.devices[i].attr_mask = attr_mask;
+
+ *handle = i;
+
+ return (HID_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function HID_HostRemoveDev
+**
+** Description This removes the device from list devices that host has to manage.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostRemoveDev ( UINT8 dev_handle )
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ HID_HostCloseDev( dev_handle ) ;
+ hh_cb.devices[dev_handle].in_use = FALSE;
+ hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
+ hh_cb.devices[dev_handle].conn.ctrl_cid = hh_cb.devices[dev_handle].conn.intr_cid = 0;
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function HID_HostOpenDev
+**
+** Description This function is called when the user wants to initiate a
+** connection attempt to a device.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostOpenDev ( UINT8 dev_handle )
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ if( hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN )
+ return HID_ERR_ALREADY_CONN;
+
+ hh_cb.devices[dev_handle].conn_tries = 1;
+ return hidh_conn_initiate( dev_handle );
+}
+
+/*******************************************************************************
+**
+** Function HID_HostWriteDev
+**
+** Description This function is called when the host has a report to send.
+**
+** report_id: is only used on GET_REPORT transaction if is specified.
+** only valid when it's a non-zero value.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostWriteDev( UINT8 dev_handle, UINT8 t_type,
+ UINT8 param, UINT16 data, UINT8 report_id, BT_HDR *pbuf )
+{
+ tHID_STATUS status = HID_SUCCESS;
+
+ if( !hh_cb.reg_flag )
+ {
+ HIDH_TRACE_ERROR0("HID_ERR_NOT_REGISTERED");
+ status = HID_ERR_NOT_REGISTERED;
+ }
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ {
+ HIDH_TRACE_ERROR0("HID_ERR_INVALID_PARAM");
+ status = HID_ERR_INVALID_PARAM;
+ }
+
+ else if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
+ {
+ HIDH_TRACE_ERROR1("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle);
+ status = HID_ERR_NO_CONNECTION;
+ }
+
+ if (status != HID_SUCCESS)
+ {
+ if (pbuf)
+ GKI_freebuf ((void *)pbuf);
+ }
+ else
+ status = hidh_conn_snd_data( dev_handle, t_type, param, data, report_id, pbuf ) ;
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function HID_HostCloseDev
+**
+** Description This function disconnects the device.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostCloseDev( UINT8 dev_handle )
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+ btu_stop_timer( &(hh_cb.devices[dev_handle].conn.timer_entry) ) ;
+
+ if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
+ return HID_ERR_NO_CONNECTION;
+
+ hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+ return hidh_conn_disconnect( dev_handle );
+}
+
+tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl )
+{
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 1 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 2 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 3 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 4 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 5 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+ {
+ HIDH_TRACE_ERROR0 ("Security Registration 6 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ return( HID_SUCCESS );
+}
+
+/******************************************************************************
+**
+** Function hid_known_hid_device
+**
+** Description check if this device is of type HID Device
+**
+** Returns TRUE if device is HID Device else FALSE
+**
+*******************************************************************************/
+BOOLEAN hid_known_hid_device (BD_ADDR bd_addr)
+{
+ UINT8 i;
+ tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(bd_addr);
+
+ if ( !hh_cb.reg_flag )
+ return FALSE;
+
+ /* First check for class of device , if Inq DB has information about this device*/
+ if (p_inq_info != NULL)
+ {
+ /* Check if remote major device class is of type BTM_COD_MAJOR_PERIPHERAL */
+ if ((p_inq_info->results.dev_class[1] & BTM_COD_MAJOR_CLASS_MASK)
+ == BTM_COD_MAJOR_PERIPHERAL )
+ {
+ HIDH_TRACE_DEBUG0("hid_known_hid_device:dev found in InqDB & COD matches HID dev");
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* Look for this device in security device DB */
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+ if ((p_dev_rec != NULL) &&
+ ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL ))
+ {
+ HIDH_TRACE_DEBUG0("hid_known_hid_device:dev found in SecDevDB & COD matches HID dev");
+ return TRUE;
+ }
+ }
+
+ /* Find an entry for this device in hh_cb.devices array */
+ for ( i=0; i<HID_HOST_MAX_DEVICES; i++)
+ {
+ if ((hh_cb.devices[i].in_use) &&
+ (memcmp(bd_addr, hh_cb.devices[i].addr, BD_ADDR_LEN) == 0))
+ return TRUE;
+ }
+ /* Check if this device is marked as HID Device in IOP Dev */
+ HIDH_TRACE_DEBUG0("hid_known_hid_device:remote is not HID device");
+ return FALSE;
+}
diff --git a/stack/hid/hidd_conn.c b/stack/hid/hidd_conn.c
new file mode 100644
index 000000000..86b41d36f
--- /dev/null
+++ b/stack/hid/hidd_conn.c
@@ -0,0 +1,1043 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the connection interface functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#include "gki.h"
+#include "bt_types.h"
+
+#include "l2cdefs.h"
+#include "l2c_api.h"
+
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+#include "hiddefs.h"
+
+#include "hidh_api.h"
+#include "hidh_int.h"
+#include "bt_utils.h"
+
+static UINT8 find_conn_by_cid (UINT16 cid);
+static void hidh_conn_retry (UINT8 dhandle);
+
+/********************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/********************************************************************************/
+static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid,
+ UINT16 psm, UINT8 l2cap_id);
+static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
+static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
+static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
+static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
+
+static const tL2CAP_APPL_INFO hst_reg_info =
+{
+ hidh_l2cif_connect_ind,
+ hidh_l2cif_connect_cfm,
+ NULL,
+ hidh_l2cif_config_ind,
+ hidh_l2cif_config_cfm,
+ hidh_l2cif_disconnect_ind,
+ hidh_l2cif_disconnect_cfm,
+ NULL,
+ hidh_l2cif_data_ind,
+ hidh_l2cif_cong_ind,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_reg
+**
+** Description This function initializes the SDP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_reg (void)
+{
+ int xx;
+
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ hh_cb.l2cap_cfg.mtu_present = TRUE;
+ hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
+ hh_cb.l2cap_cfg.flush_to_present = TRUE;
+ hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
+ {
+ HIDH_TRACE_ERROR0 ("HID Control Registration failed");
+ return (HID_ERR_L2CAP_FAILED) ;
+ }
+ if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info))
+ {
+ L2CA_Deregister( HID_PSM_CONTROL ) ;
+ HIDH_TRACE_ERROR0 ("HID Interrupt Registration failed");
+ return (HID_ERR_L2CAP_FAILED) ;
+ }
+
+ for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
+ {
+ hh_cb.devices[xx].in_use = FALSE ;
+ hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_disconnect
+**
+** Description This function disconnects a connection.
+**
+** Returns TRUE if disconnect started, FALSE if already disconnected
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
+{
+ tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+
+ HIDH_TRACE_EVENT0 ("HID-Host disconnect");
+
+ if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ /* Disconnect both interrupt and control channels */
+ if (p_hcon->intr_cid)
+ L2CA_DisconnectReq (p_hcon->intr_cid);
+
+ if (p_hcon->ctrl_cid)
+ L2CA_DisconnectReq (p_hcon->ctrl_cid);
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function hidh_sec_check_complete_term
+**
+** Description HID security check complete callback function.
+**
+** Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
+** send security block L2C connection response.
+**
+*******************************************************************************/
+void hidh_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
+ UNUSED(bd_addr);
+
+ if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+ {
+ p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
+
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
+
+ }
+ /* security check fail */
+ else if (res != BTM_SUCCESS)
+ {
+ p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+ L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_connect_ind
+**
+** Description This function handles an inbound connection indication
+** from L2CAP. This is the case where we are acting as a
+** server.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
+{
+ tHID_CONN *p_hcon;
+ BOOLEAN bAccept = TRUE;
+ UINT8 i = HID_HOST_MAX_DEVICES;
+ tHID_HOST_DEV_CTB *p_dev;
+
+ HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
+
+ /* always add incoming connection device into HID database by default */
+ if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
+ return;
+ }
+
+ p_hcon = &hh_cb.devices[i].conn;
+ p_dev = &hh_cb.devices[i];
+
+ /* Check we are in the correct state for this */
+ if (psm == HID_PSM_INTERRUPT)
+ {
+ if (p_hcon->ctrl_cid == 0)
+ {
+ HIDH_TRACE_WARNING0 ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
+ bAccept = FALSE;
+ }
+ if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
+ p_hcon->conn_state);
+ bAccept = FALSE;
+ }
+ }
+ else /* CTRL channel */
+ {
+#if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
+ p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+#else
+ if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
+ p_hcon->conn_state);
+ bAccept = FALSE;
+ }
+#endif
+ }
+
+ if (!bAccept)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+
+ if (psm == HID_PSM_CONTROL)
+ {
+ p_hcon->conn_flags = 0;
+ p_hcon->ctrl_cid = l2cap_cid;
+ p_hcon->ctrl_id = l2cap_id;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
+
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ FALSE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+ {
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+
+ return;
+ }
+
+ /* Transition to the next appropriate state, configuration */
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ p_hcon->intr_cid = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
+
+ HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x",
+ psm, l2cap_cid);
+}
+
+/*******************************************************************************
+**
+** Function hidh_proc_repage_timeout
+**
+** Description This function handles timeout (to page device).
+**
+** Returns void
+**
+*******************************************************************************/
+void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
+{
+ hidh_conn_initiate( (UINT8) p_tle->param ) ;
+ hh_cb.devices[p_tle->param].conn_tries++;
+ hh_cb.callback( (UINT8) p_tle->param, hh_cb.devices[p_tle->param].addr,
+ HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
+}
+
+/*******************************************************************************
+**
+** Function hidh_sec_check_complete_orig
+**
+** Description This function checks to see if security procedures are being
+** carried out or not..
+**
+** Returns void
+**
+*******************************************************************************/
+void hidh_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
+{
+ tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
+ UINT8 dhandle;
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ UINT32 cb_res = HID_ERR_AUTH_FAILED;
+#endif
+ UINT32 reason;
+ UNUSED(bd_addr);
+
+ dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
+ if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+ {
+ HIDH_TRACE_EVENT0 ("HID-Host Originator security pass.");
+ p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
+
+ /* Check if L2CAP started the connection process for interrupt channel */
+ if ((p_dev->conn.intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
+ {
+ HIDH_TRACE_WARNING0 ("HID-Host INTR Originate failed");
+ reason = HID_L2CAP_REQ_FAIL ;
+ hidh_conn_disconnect (dhandle);
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ return;
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+
+ if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+ {
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if( res == BTM_DEVICE_TIMEOUT )
+ {
+ if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
+ {
+ hidh_conn_retry (dhandle);
+ return;
+ }
+ else
+ cb_res = HID_L2CAP_CONN_FAIL | HCI_ERR_PAGE_TIMEOUT ;
+ }
+#endif
+ p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
+ hidh_conn_disconnect(dhandle);
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_connect_cfm
+**
+** Description This function handles the connect confirm events
+** from L2CAP. This is the case when we are acting as a
+** client and have sent a connect request.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UINT32 reason;
+ tHID_HOST_DEV_CTB *p_dev = NULL;
+
+ /* Find CCB based on CID, and verify we are in a state to accept this message */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ {
+ p_dev = &hh_cb.devices[dhandle];
+ p_hcon = &hh_cb.devices[dhandle].conn;
+ }
+
+ if ((p_hcon == NULL)
+ || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
+ || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
+ || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)))
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
+ return;
+ }
+
+ if (result != L2CAP_CONN_OK)
+ {
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ hidh_conn_disconnect(dhandle);
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
+ (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
+ result == HCI_ERR_PAGE_TIMEOUT) )
+ {
+ hidh_conn_retry(dhandle);
+ }
+ else
+#endif
+ {
+ reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ }
+ return;
+ }
+ /* receive Control Channel connect confirmation */
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ {
+ /* check security requirement */
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
+
+ btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+ TRUE, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_orig, p_dev);
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ }
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
+
+ HIDH_TRACE_EVENT1 ("HID-Host got CTRL conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_config_ind
+**
+** Description This function processes the L2CAP configuration indication
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ tHID_HOST_DEV_CTB *p_dev;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ {
+ p_dev = &hh_cb.devices[dhandle];
+ p_hcon = &hh_cb.devices[dhandle].conn;
+ }
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT1 ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ /* Remember the remote MTU size */
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
+ p_hcon->rem_mtu_size = HID_HOST_MTU;
+ else
+ p_hcon->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+ else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+ && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+
+ hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_config_cfm
+**
+** Description This function processes the L2CAP configuration confirmation
+** event.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UINT32 reason;
+
+ HIDH_TRACE_EVENT2 ("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If configuration failed, disconnect the channel(s) */
+ if (p_cfg->result != L2CAP_CFG_OK)
+ {
+ hidh_conn_disconnect (dhandle);
+ reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+ return;
+ }
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+ else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+ && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+
+ hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_disconnect_ind
+**
+** Description This function handles a disconnect event from L2CAP. If
+** requested to, we ack the disconnect before dropping the CCB
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UINT16 disc_res = HCI_SUCCESS;
+ UINT16 hid_close_evt_reason;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (ack_needed)
+ L2CA_DisconnectRsp (l2cap_cid);
+
+ HIDH_TRACE_EVENT1 ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+ {
+ hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ if( !ack_needed )
+ disc_res = btm_get_acl_disc_reason_code();
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
+ (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
+ (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
+ {
+ hh_cb.devices[dhandle].conn_tries = 0;
+ hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle;
+ btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
+ }
+ else
+#endif
+ {
+ /* Set reason code for HID_HDEV_EVT_CLOSE */
+ hid_close_evt_reason = p_hcon->disc_reason;
+
+ /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
+ if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
+ (disc_res == HCI_ERR_KEY_MISSING) ||
+ (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (disc_res == HCI_ERR_UNIT_KEY_USED) ||
+ (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
+ (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
+ {
+ hid_close_evt_reason = HID_ERR_AUTH_FAILED;
+ }
+
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_disconnect_cfm
+**
+** Description This function handles a disconnect confirm event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+ UNUSED(result);
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT1 ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+ {
+ hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_cong_ind
+**
+** Description This function handles a congestion status event from L2CAP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
+{
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+
+ /* Find CCB based on CID */
+ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", l2cap_cid, congested);
+
+ if (congested)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+ else
+ {
+ p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidh_l2cif_data_ind
+**
+** Description This function is called when data is received from L2CAP.
+** if we are the originator of the connection, we are the SDP
+** client, and the received message is queued up for the client.
+**
+** If we are the destination of the connection, we are the SDP
+** server, so the message is passed to the server processing
+** function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
+{
+ UINT8 *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 ttype, param, rep_type, evt;
+ UINT8 dhandle;
+ tHID_CONN *p_hcon = NULL;
+
+ HIDH_TRACE_DEBUG1 ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
+
+ /* Find CCB based on CID */
+ if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
+ p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL)
+ {
+ HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ GKI_freebuf (p_msg);
+ return;
+ }
+
+
+ ttype = HID_GET_TRANS_FROM_HDR(*p_data);
+ param = HID_GET_PARAM_FROM_HDR(*p_data);
+ rep_type = param & HID_PAR_REP_TYPE_MASK;
+ p_data++;
+
+ /* Get rid of the data type */
+ p_msg->len--;
+ p_msg->offset++;
+
+ switch (ttype)
+ {
+ case HID_TRANS_HANDSHAKE:
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
+ GKI_freebuf (p_msg);
+ break;
+
+ case HID_TRANS_CONTROL:
+ switch (param)
+ {
+ case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+ hidh_conn_disconnect( dhandle ) ;
+ /* Device is unplugging from us. Tell USB */
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
+ break;
+
+ default:
+ break;
+ }
+ GKI_freebuf (p_msg);
+ break;
+
+
+ case HID_TRANS_DATA:
+ evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
+ HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
+ break;
+
+ case HID_TRANS_DATAC:
+ evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
+ HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
+ break;
+
+ default:
+ GKI_freebuf (p_msg);
+ break;
+ }
+
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_snd_data
+**
+** Description This function is sends out data.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
+ UINT16 data, UINT8 report_id, BT_HDR *buf)
+{
+ tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+ BT_HDR *p_buf;
+ UINT8 *p_out;
+ UINT16 bytes_copied;
+ BOOLEAN seg_req = FALSE;
+ UINT16 data_size;
+ UINT16 cid;
+ UINT8 pool_id;
+ UINT8 use_data = 0 ;
+ BOOLEAN blank_datc = FALSE;
+
+ if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
+ {
+ if (buf)
+ GKI_freebuf ((void *)buf);
+ return( HID_ERR_CONGESTED );
+ }
+
+ switch( trans_type )
+ {
+ case HID_TRANS_CONTROL:
+ case HID_TRANS_GET_REPORT:
+ case HID_TRANS_SET_REPORT:
+ case HID_TRANS_GET_PROTOCOL:
+ case HID_TRANS_SET_PROTOCOL:
+ case HID_TRANS_GET_IDLE:
+ case HID_TRANS_SET_IDLE:
+ cid = p_hcon->ctrl_cid;
+ pool_id = HID_CONTROL_POOL_ID;
+ break;
+ case HID_TRANS_DATA:
+ cid = p_hcon->intr_cid;
+ pool_id = HID_INTERRUPT_POOL_ID;
+ break;
+ default:
+ return (HID_ERR_INVALID_PARAM) ;
+ }
+
+ if( trans_type == HID_TRANS_SET_IDLE )
+ use_data = 1;
+ else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
+ use_data = 2;
+
+ do
+ {
+ if ( buf == NULL || blank_datc )
+ {
+ if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
+ return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = FALSE;
+ data_size = 0;
+ bytes_copied = 0;
+ blank_datc = FALSE;
+ }
+ else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
+ {
+ if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
+ return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = TRUE;
+ data_size = buf->len;
+ bytes_copied = p_hcon->rem_mtu_size - 1;
+ }
+ else
+ {
+ p_buf = buf ;
+ p_buf->offset -= 1;
+ seg_req = FALSE;
+ data_size = buf->len;
+ bytes_copied = buf->len;
+ }
+
+ p_out = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ *p_out++ = HID_BUILD_HDR(trans_type, param);
+
+ /* If report ID required for this device */
+ if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
+ {
+ *p_out = report_id;
+ data_size = bytes_copied = 1;
+ }
+
+
+ if (seg_req)
+ {
+ memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
+ buf->offset += bytes_copied;
+ buf->len -= bytes_copied;
+ }
+ else if( use_data == 1)
+ {
+ *(p_out+bytes_copied) = data & 0xff;
+ }
+ else if( use_data == 2 )
+ {
+ *(p_out+bytes_copied) = data & 0xff;
+ *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
+ }
+
+ p_buf->len = bytes_copied + 1 + use_data;
+ data_size -= bytes_copied;
+
+ /* Send the buffer through L2CAP */
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
+ return (HID_ERR_CONGESTED);
+
+ if (data_size)
+ trans_type = HID_TRANS_DATAC;
+ else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
+ {
+ trans_type = HID_TRANS_DATAC;
+ blank_datc = TRUE;
+ }
+
+ } while ((data_size != 0) || blank_datc ) ;
+
+ return (HID_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function hidh_conn_initiate
+**
+** Description This function is called by the management to create a connection.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
+{
+ UINT8 service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
+ UINT32 mx_chan_id = HID_NOSEC_CHN;
+
+ tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
+
+ if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
+ return( HID_ERR_CONN_IN_PROCESS );
+
+ p_dev->conn.ctrl_cid = 0;
+ p_dev->conn.intr_cid = 0;
+ p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
+
+ /* We are the originator of this connection */
+ p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
+
+ if(p_dev->attr_mask & HID_SEC_REQUIRED)
+ {
+ service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
+ mx_chan_id = HID_SEC_CHN;
+ }
+ BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
+
+ /* Check if L2CAP started the connection process */
+ if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
+ {
+ HIDH_TRACE_WARNING0 ("HID-Host Originate failed");
+ hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ HID_ERR_L2CAP_FAILED, NULL ) ;
+ }
+ else
+ {
+ /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+ }
+
+ return( HID_SUCCESS );
+}
+
+
+/*******************************************************************************
+**
+** Function find_conn_by_cid
+**
+** Description This function finds a connection control block based on CID
+**
+** Returns address of control block, or NULL if not found
+**
+*******************************************************************************/
+static UINT8 find_conn_by_cid (UINT16 cid)
+{
+ UINT8 xx;
+
+ for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
+ {
+ if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
+ && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
+ break;
+ }
+
+ return (xx);
+}
+
+void hidh_conn_dereg( void )
+{
+ L2CA_Deregister (HID_PSM_CONTROL);
+ L2CA_Deregister (HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_retry
+**
+** Description This function is called to retry a failed connection.
+**
+** Returns void
+**
+*******************************************************************************/
+static void hidh_conn_retry( UINT8 dhandle )
+{
+ tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
+
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+ p_dev->conn.timer_entry.param = (UINT32) dhandle;
+#if (HID_HOST_REPAGE_WIN > 0)
+ btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
+#else
+ hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );
+#endif
+}
diff --git a/stack/hid/hidd_int.h b/stack/hid/hidd_int.h
new file mode 100644
index 000000000..ad074129c
--- /dev/null
+++ b/stack/hid/hidd_int.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains HID HOST internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDH_INT_H
+#define HIDH_INT_H
+
+#include "hidh_api.h"
+#include "hid_conn.h"
+#include "l2c_api.h"
+
+enum {
+ HID_DEV_NO_CONN,
+ HID_DEV_CONNECTED
+};
+
+typedef struct per_device_ctb
+{
+ BOOLEAN in_use;
+ BD_ADDR addr; /* BD-Addr of the host device */
+ UINT16 attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03- reconn_initiate;
+ 0x04- sdp_disable; */
+ UINT8 state; /* Device state if in HOST-KNOWN mode */
+ UINT8 conn_substate;
+ UINT8 conn_tries; /* Remembers to the number of connection attempts while CONNECTING */
+
+ tHID_CONN conn; /* L2CAP channel info */
+} tHID_HOST_DEV_CTB;
+
+typedef struct host_ctb
+{
+ tHID_HOST_DEV_CTB devices[HID_HOST_MAX_DEVICES];
+ tHID_HOST_DEV_CALLBACK *callback; /* Application callbacks */
+ tL2CAP_CFG_INFO l2cap_cfg;
+
+#define MAX_SERVICE_DB_SIZE 4000
+
+ BOOLEAN sdp_busy;
+ tHID_HOST_SDP_CALLBACK *sdp_cback;
+ tSDP_DISCOVERY_DB *p_sdp_db;
+ tHID_DEV_SDP_INFO sdp_rec;
+ BOOLEAN reg_flag;
+ UINT8 trace_level;
+} tHID_HOST_CTB;
+
+extern tHID_STATUS hidh_conn_snd_data(UINT8 dhandle, UINT8 trans_type, UINT8 param, \
+ UINT16 data,UINT8 rpt_id, BT_HDR *buf);
+extern tHID_STATUS hidh_conn_reg (void);
+extern void hidh_conn_dereg( void );
+extern tHID_STATUS hidh_conn_disconnect (UINT8 dhandle);
+extern tHID_STATUS hidh_conn_initiate (UINT8 dhandle);
+extern void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+#if HID_DYNAMIC_MEMORY == FALSE
+HID_API extern tHID_HOST_CTB hh_cb;
+#else
+HID_API extern tHID_HOST_CTB *hidh_cb_ptr;
+#define hh_cb (*hidh_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/stack/include/hidd_api.h b/stack/include/hidd_api.h
new file mode 100644
index 000000000..27e8ac5de
--- /dev/null
+++ b/stack/include/hidd_api.h
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef HIDH_API_H
+#define HIDH_API_H
+
+#include "hiddefs.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+enum {
+ HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER+1),
+ HID_SDP_MANDATORY_MISSING
+};
+
+/* Attributes mask values to be used in HID_HostAddDev API */
+#define HID_VIRTUAL_CABLE 0x0001
+#define HID_NORMALLY_CONNECTABLE 0x0002
+#define HID_RECONN_INIT 0x0004
+#define HID_SDP_DISABLE 0x0008
+#define HID_BATTERY_POWER 0x0010
+#define HID_REMOTE_WAKE 0x0020
+#define HID_SUP_TOUT_AVLBL 0x0040
+#define HID_SSR_MAX_LATENCY 0x0080
+#define HID_SSR_MIN_TOUT 0x0100
+
+#define HID_SEC_REQUIRED 0x8000
+#define HID_ATTR_MASK_IGNORE 0
+
+
+/*****************************************************************************
+** Type Definitions
+*****************************************************************************/
+
+typedef void (tHID_HOST_SDP_CALLBACK) (UINT16 result, UINT16 attr_mask,
+ tHID_DEV_SDP_INFO *sdp_rec );
+
+/* HID-HOST returns the events in the following table to the application via tHID_HOST_DEV_CALLBACK
+HID_HDEV_EVT_OPEN Connected to device with Interrupt and Control Channels in OPEN state.
+ Data = NA
+HID_HDEV_EVT_CLOSE Connection with device is closed. Data=reason code.
+HID_HDEV_EVT_RETRYING Lost connection is being re-connected.
+ Data=Retrial number
+HID_HDEV_EVT_IN_REPORT Device sent an input report Data=Report Type pdata= pointer to BT_HDR
+ (GKI buffer having report data.)
+HID_HDEV_EVT_HANDSHAKE Device sent SET_REPORT Data=Result-code pdata=NA.
+HID_HDEV_EVT_VC_UNPLUG Device sent Virtual Unplug Data=NA. pdata=NA.
+*/
+
+enum
+{
+ HID_HDEV_EVT_OPEN,
+ HID_HDEV_EVT_CLOSE,
+ HID_HDEV_EVT_RETRYING,
+ HID_HDEV_EVT_INTR_DATA,
+ HID_HDEV_EVT_INTR_DATC,
+ HID_HDEV_EVT_CTRL_DATA,
+ HID_HDEV_EVT_CTRL_DATC,
+ HID_HDEV_EVT_HANDSHAKE,
+ HID_HDEV_EVT_VC_UNPLUG
+};
+typedef void (tHID_HOST_DEV_CALLBACK) (UINT8 dev_handle,
+ BD_ADDR addr,
+ UINT8 event, /* Event from HID-DEVICE. */
+ UINT32 data, /* Integer data corresponding to the event.*/
+ BT_HDR *p_buf ); /* Pointer data corresponding to the event. */
+
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*******************************************************************************
+**
+** Function HID_HostGetSDPRecord
+**
+** Description This function reads the device SDP record.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostGetSDPRecord (BD_ADDR addr,
+ tSDP_DISCOVERY_DB *p_db,
+ UINT32 db_len,
+ tHID_HOST_SDP_CALLBACK *sdp_cback );
+
+/*******************************************************************************
+**
+** Function HID_HostRegister
+**
+** Description This function registers HID-Host with lower layers.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback);
+
+/*******************************************************************************
+**
+** Function HID_HostDeregister
+**
+** Description This function is called when the host is about power down.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostDeregister(void);
+
+/*******************************************************************************
+**
+** Function HID_HostAddDev
+**
+** Description This is called so HID-host may manage this device.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostAddDev (BD_ADDR addr, UINT16 attr_mask,
+ UINT8 *handle );
+
+/*******************************************************************************
+**
+** Function HID_HostRemoveDev
+**
+** Description This removes the device from list devices that host has to manage.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostRemoveDev (UINT8 dev_handle );
+
+/*******************************************************************************
+**
+** Function HID_HostOpenDev
+**
+** Description This function is called when the user wants to initiate a
+** connection attempt to a device.
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostOpenDev (UINT8 dev_handle );
+
+/*******************************************************************************
+**
+** Function HID_HostWriteDev
+**
+** Description This function is called when the host has a report to send.
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostWriteDev(UINT8 dev_handle, UINT8 t_type,
+ UINT8 param, UINT16 data,
+ UINT8 report_id, BT_HDR *pbuf);
+
+/*******************************************************************************
+**
+** Function HID_HostCloseDev
+**
+** Description This function disconnects the device.
+**
+** Returns void
+**
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostCloseDev(UINT8 dev_handle );
+
+/*******************************************************************************
+** Function HID_HostInit
+**
+** Description This function initializes the control block and trace variable
+**
+** Returns void
+*******************************************************************************/
+HID_API extern void HID_HostInit(void);
+
+/*******************************************************************************
+** Function HID_HostSetSecurityLevel
+**
+** Description This function sets the security level for the devices which
+** are marked by application as requiring security
+**
+** Returns tHID_STATUS
+*******************************************************************************/
+HID_API extern tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl );
+
+/*******************************************************************************
+**
+** Function hid_known_hid_device
+**
+** Description This function checks if this device is of type HID Device
+**
+** Returns TRUE if device exists else FALSE
+**
+*******************************************************************************/
+BOOLEAN hid_known_hid_device (BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
+** Function HID_HostSetTraceLevel
+**
+** Description This function sets the trace level for HID Host. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+HID_API extern UINT8 HID_HostSetTraceLevel (UINT8 new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HIDH_API_H */