HIDD: Add support for HID Device Role

This patch adds support for HID Device role in bluedroid stack allowing
DUT to be used as Keyboard or Mouse.

Bug: 33011576
Change-Id: I45b581a54f6c7bbc1f25226715a7ea23e34255c0
diff --git a/bta/Android.mk b/bta/Android.mk
index b3051c1..429e319 100644
--- a/bta/Android.mk
+++ b/bta/Android.mk
@@ -11,6 +11,7 @@
                    $(LOCAL_PATH)/sys \
                    $(LOCAL_PATH)/dm \
                    $(LOCAL_PATH)/hh \
+                   $(LOCAL_PATH)/hd \
                    $(LOCAL_PATH)/closure \
                    $(LOCAL_PATH)/../btcore/include \
                    $(LOCAL_PATH)/../hci/include \
@@ -76,6 +77,9 @@
     ./hh/bta_hh_le.cc \
     ./hh/bta_hh_main.cc \
     ./hh/bta_hh_utils.cc \
+    ./hd/bta_hd_act.cc \
+    ./hd/bta_hd_api.cc \
+    ./hd/bta_hd_main.cc \
     ./hl/bta_hl_act.cc \
     ./hl/bta_hl_api.cc \
     ./hl/bta_hl_ci.cc \
diff --git a/bta/BUILD.gn b/bta/BUILD.gn
index 47eae82..ff477f0 100644
--- a/bta/BUILD.gn
+++ b/bta/BUILD.gn
@@ -64,6 +64,10 @@
     "hh/bta_hh_le.cc",
     "hh/bta_hh_main.cc",
     "hh/bta_hh_utils.cc",
+    "hd/bta_hd_utils.cc",
+    "hd/bta_hd_act.cc",
+    "hd/bta_hd_api.cc",
+    "hd/bta_hd_main.cc",
     "hl/bta_hl_act.cc",
     "hl/bta_hl_api.cc",
     "hl/bta_hl_ci.cc",
@@ -95,6 +99,7 @@
     "closure",
     "dm",
     "hh",
+    "hd",
     "include",
     "sys",
     "//",
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 4d018dd..06ffd39 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -3902,6 +3902,22 @@
   }
 }
 
+bool bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr) {
+  APPL_TRACE_DEBUG("%s: count(%d)", __func__, bta_dm_conn_srvcs.count);
+
+  for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) {
+    // Check if profiles other than hid are connected
+    if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) &&
+        !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
+      APPL_TRACE_DEBUG("%s: Another profile (id=%d) is connected", __func__,
+                       bta_dm_conn_srvcs.conn_srvc[j].id);
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
 /*******************************************************************************
  *
  * Function         bta_dm_observe_results_cb
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 1d0ce9e..787e11a 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -557,12 +557,12 @@
 tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
     /*max_lat, min_rmt_to, min_loc_to*/
     {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */
-    {0, 0,
-     2}, /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile,
-            seting default max latency and min remote timeout as 0,
-            and always read individual device preference from HH module */
-    {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
-    {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */
+    /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile, seting
+       default max latency and min remote timeout as 0, and always read
+       individual device preference from HH module */
+    {0, 0, 2},
+    {1200, 2, 2},    /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
+    {360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
 };
 
 tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC*)&bta_dm_ssr_spec;
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index 62a473f..7c6eaf9 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -257,8 +257,8 @@
     } else
       bta_gattc_deregister_cmpl(p_clreg);
   } else {
-    APPL_TRACE_ERROR(
-        "bta_gattc_deregister Deregister Failedm unknown client cif");
+    APPL_TRACE_ERROR("%s: Deregister Failed unknown client cif", __func__);
+    bta_hh_cleanup_disable(BTA_HH_OK);
   }
 }
 /*******************************************************************************
diff --git a/bta/hd/bta_hd_act.cc b/bta/hd/bta_hd_act.cc
new file mode 100644
index 0000000..a8a43d1
--- /dev/null
+++ b/bta/hd/bta_hd_act.cc
@@ -0,0 +1,708 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 device action functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_hd_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+#include "osi/include/osi.h"
+
+static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data,
+                         BT_HDR* pdata);
+
+static bool check_descriptor(uint8_t* data, uint16_t length,
+                             bool* has_report_id) {
+  uint8_t* ptr = data;
+
+  *has_report_id = FALSE;
+
+  while (ptr < data + length) {
+    uint8_t item = *ptr++;
+
+    switch (item) {
+      case 0xfe:  // long item indicator
+        ptr += ((*ptr) + 2);
+        break;
+
+      case 0x85:  // Report ID
+        *has_report_id = TRUE;
+
+      default:
+        ptr += (item & 0x03);
+        break;
+    }
+  }
+
+  return (ptr == data + length);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_api_enable
+ *
+ * Description      Enables HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_api_enable(tBTA_HD_DATA* p_data) {
+  tBTA_HD_STATUS status = BTA_HD_ERROR;
+  tHID_STATUS ret;
+
+  APPL_TRACE_API("%s", __func__);
+
+  HID_DevInit();
+
+  memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+
+  HID_DevSetSecurityLevel(BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+  /* store parameters */
+  bta_hd_cb.p_cback = p_data->api_enable.p_cback;
+
+  if ((ret = HID_DevRegister(bta_hd_cback)) == HID_SUCCESS) {
+    status = BTA_HD_OK;
+  } else {
+    APPL_TRACE_ERROR("%s: Failed to register HID device (%d)", __func__, ret);
+  }
+
+  /* signal BTA call back event */
+  (*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_api_disable
+ *
+ * Description      Disables HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_api_disable(void) {
+  tBTA_HD_STATUS status = BTA_HD_ERROR;
+  tHID_STATUS ret;
+
+  APPL_TRACE_API("%s", __func__);
+
+  /* service is not enabled */
+  if (bta_hd_cb.p_cback == NULL) return;
+
+  /* Remove service record */
+  if (bta_hd_cb.sdp_handle != 0) {
+    SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+    bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+  }
+
+  /* Deregister with lower layer */
+  if ((ret = HID_DevDeregister()) == HID_SUCCESS) {
+    status = BTA_HD_OK;
+  } else {
+    APPL_TRACE_ERROR("%s: Failed to deregister HID device (%s)", __func__, ret);
+  }
+
+  (*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, (tBTA_HD*)&status);
+
+  memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_register_act
+ *
+ * Description      Registers SDP record
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_register_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD ret;
+  tBTA_HD_REGISTER_APP* p_app_data = (tBTA_HD_REGISTER_APP*)p_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  ret.reg_status.in_use = FALSE;
+
+  /* Check if len doesn't exceed BTA_HD_APP_DESCRIPTOR_LEN */
+  if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN) {
+    ret.reg_status.status = BTA_HD_ERROR;
+    (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
+    return;
+  }
+
+  ret.reg_status.status = BTA_HD_OK;
+
+  /* Remove old record if for some reason it's already registered */
+  if (bta_hd_cb.sdp_handle != 0) {
+    SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+  }
+
+  // need to check if descriptor has Report Id item so we know if report will
+  // have prefix or not
+  check_descriptor(p_app_data->d_data, p_app_data->d_len,
+                   &bta_hd_cb.use_report_id);
+
+  bta_hd_cb.sdp_handle = SDP_CreateRecord();
+  HID_DevAddRecord(bta_hd_cb.sdp_handle, p_app_data->name,
+                   p_app_data->description, p_app_data->provider,
+                   p_app_data->subclass, p_app_data->d_len, p_app_data->d_data);
+  bta_sys_add_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+
+  HID_DevSetIncomingQos(
+      p_app_data->in_qos.service_type, p_app_data->in_qos.token_rate,
+      p_app_data->in_qos.token_bucket_size, p_app_data->in_qos.peak_bandwidth,
+      p_app_data->in_qos.access_latency, p_app_data->in_qos.delay_variation);
+
+  HID_DevSetOutgoingQos(
+      p_app_data->out_qos.service_type, p_app_data->out_qos.token_rate,
+      p_app_data->out_qos.token_bucket_size, p_app_data->out_qos.peak_bandwidth,
+      p_app_data->out_qos.access_latency, p_app_data->out_qos.delay_variation);
+
+  // application is registered so we can accept incoming connections
+  HID_DevSetIncomingPolicy(TRUE);
+
+  if (HID_DevGetDevice(&ret.reg_status.bda) == HID_SUCCESS) {
+    ret.reg_status.in_use = TRUE;
+  }
+
+  (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_unregister_act
+ *
+ * Description      Unregisters SDP record
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_unregister_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+  tBTA_HD_STATUS status = BTA_HD_OK;
+
+  APPL_TRACE_API("%s", __func__);
+
+  // application is no longer registered so we do not want incoming connections
+  HID_DevSetIncomingPolicy(FALSE);
+
+  if (bta_hd_cb.sdp_handle != 0) {
+    SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+  }
+
+  bta_hd_cb.sdp_handle = 0;
+  bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+
+  (*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, (tBTA_HD*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_unregister2_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_unregister2_act(tBTA_HD_DATA* p_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  // close first
+  bta_hd_close_act(p_data);
+
+  // then unregister
+  bta_hd_unregister_act(p_data);
+
+  if (bta_hd_cb.disable_w4_close) {
+    bta_hd_api_disable();
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_connect_act
+ *
+ * Description      Connect to device (must be virtually plugged)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_connect_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+  tHID_STATUS ret;
+
+  APPL_TRACE_API("%s", __func__);
+
+  ret = HID_DevConnect();
+
+  if (ret != HID_SUCCESS) {
+    APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_disconnect_act
+ *
+ * Description      Disconnect from device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_disconnect_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+  tHID_STATUS ret;
+
+  APPL_TRACE_API("%s", __func__);
+
+  ret = HID_DevDisconnect();
+
+  if (ret != HID_SUCCESS) {
+    APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_add_device_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_add_device_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  HID_DevPlugDevice(p_ctrl->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_remove_device_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_remove_device_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  HID_DevUnplugDevice(p_ctrl->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_send_report_act
+ *
+ * Description      Sends report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_send_report_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_SEND_REPORT* p_report = (tBTA_HD_SEND_REPORT*)p_data;
+  uint8_t channel;
+  uint8_t report_id;
+
+  APPL_TRACE_VERBOSE("%s", __func__);
+
+  channel = p_report->use_intr ? HID_CHANNEL_INTR : HID_CHANNEL_CTRL;
+  report_id =
+      (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) ? p_report->id : 0x00;
+
+  HID_DevSendReport(channel, p_report->type, report_id, p_report->len,
+                    p_report->data);
+
+  /* trigger PM */
+  bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+  bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_report_error_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_report_error_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_REPORT_ERR* p_report = (tBTA_HD_REPORT_ERR*)p_data;
+  tHID_STATUS ret;
+
+  APPL_TRACE_API("%s: error = %d", __func__, p_report->error);
+
+  ret = HID_DevReportError(p_report->error);
+
+  if (ret != HID_SUCCESS) {
+    APPL_TRACE_WARNING("%s: HID_DevReportError returned %d", __func__, ret);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_vc_unplug_act
+ *
+ * Description      Sends Virtual Cable Unplug
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_vc_unplug_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+  tHID_STATUS ret;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_hd_cb.vc_unplug = TRUE;
+
+  ret = HID_DevVirtualCableUnplug();
+
+  if (ret != HID_SUCCESS) {
+    APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__,
+                       ret);
+  }
+
+  /* trigger PM */
+  bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+  bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_open_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_open_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  tBTA_HD cback_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  HID_DevPlugDevice(p_cback->addr);
+  bta_sys_conn_open(BTA_ID_HD, 1, p_cback->addr);
+
+  bdcpy(cback_data.conn.bda, p_cback->addr);
+  bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
+
+  bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_close_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_close_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  tBTA_HD cback_data;
+  tBTA_HD_EVT cback_event = BTA_HD_CLOSE_EVT;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
+
+  if (bta_hd_cb.vc_unplug) {
+    bta_hd_cb.vc_unplug = FALSE;
+    HID_DevUnplugDevice(p_cback->addr);
+    cback_event = BTA_HD_VC_UNPLUG_EVT;
+  }
+
+  bdcpy(cback_data.conn.bda, p_cback->addr);
+  memset(bta_hd_cb.bd_addr, 0, sizeof(BD_ADDR));
+
+  bta_hd_cb.p_cback(cback_event, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_intr_data_act
+ *
+ * Description      Handles incoming DATA request on intr
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_intr_data_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  BT_HDR* p_msg = p_cback->p_data;
+  uint16_t len = p_msg->len;
+  uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset;
+  tBTA_HD_INTR_DATA ret;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
+    ret.report_id = *p_buf;
+
+    len--;
+    p_buf++;
+  } else {
+    ret.report_id = 0;
+  }
+
+  ret.len = len;
+  ret.p_data = p_buf;
+
+  (*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_get_report_act
+ *
+ * Description      Handles incoming GET_REPORT request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_get_report_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  bool rep_size_follows = p_cback->data;
+  BT_HDR* p_msg = p_cback->p_data;
+  uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset;
+  tBTA_HD_GET_REPORT ret = {0, 0, 0};
+
+  APPL_TRACE_API("%s", __func__);
+
+  ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+  p_buf++;
+
+  if (bta_hd_cb.use_report_id) {
+    ret.report_id = *p_buf;
+    p_buf++;
+  }
+
+  if (rep_size_follows) {
+    ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
+  }
+
+  (*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_set_report_act
+ *
+ * Description      Handles incoming SET_REPORT request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_set_report_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  BT_HDR* p_msg = p_cback->p_data;
+  uint16_t len = p_msg->len;
+  uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset;
+  tBTA_HD_SET_REPORT ret = {0, 0, 0, NULL};
+
+  APPL_TRACE_API("%s", __func__);
+
+  ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+  p_buf++;
+  len--;
+
+  if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
+    ret.report_id = *p_buf;
+
+    len--;
+    p_buf++;
+  } else {
+    ret.report_id = 0;
+  }
+
+  ret.len = len;
+  ret.p_data = p_buf;
+
+  (*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_set_protocol_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_set_protocol_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  tBTA_HD cback_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_hd_cb.boot_mode = (p_cback->data == HID_PAR_PROTOCOL_BOOT_MODE);
+  cback_data.set_protocol = p_cback->data;
+
+  (*bta_hd_cb.p_cback)(BTA_HD_SET_PROTOCOL_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_vc_unplug_done_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+  tBTA_HD cback_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
+
+  HID_DevUnplugDevice(p_cback->addr);
+
+  bdcpy(cback_data.conn.bda, p_cback->addr);
+  bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
+
+  (*bta_hd_cb.p_cback)(BTA_HD_VC_UNPLUG_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_suspend_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_suspend_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_exit_suspend_act
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hd_exit_suspend_act(tBTA_HD_DATA* p_data) {
+  tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_busy(BTA_ID_HD, 1, p_cback->addr);
+  bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_cback
+ *
+ * Description      BTA HD callback function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data,
+                         BT_HDR* pdata) {
+  tBTA_HD_CBACK_DATA* p_buf = NULL;
+  uint16_t sm_event = BTA_HD_INVALID_EVT;
+
+  APPL_TRACE_API("%s: event=%d", __func__, event);
+
+  switch (event) {
+    case HID_DHOST_EVT_OPEN:
+      sm_event = BTA_HD_INT_OPEN_EVT;
+      break;
+
+    case HID_DHOST_EVT_CLOSE:
+      sm_event = BTA_HD_INT_CLOSE_EVT;
+      break;
+
+    case HID_DHOST_EVT_GET_REPORT:
+      sm_event = BTA_HD_INT_GET_REPORT_EVT;
+      break;
+
+    case HID_DHOST_EVT_SET_REPORT:
+      sm_event = BTA_HD_INT_SET_REPORT_EVT;
+      break;
+
+    case HID_DHOST_EVT_SET_PROTOCOL:
+      sm_event = BTA_HD_INT_SET_PROTOCOL_EVT;
+      break;
+
+    case HID_DHOST_EVT_INTR_DATA:
+      sm_event = BTA_HD_INT_INTR_DATA_EVT;
+      break;
+
+    case HID_DHOST_EVT_VC_UNPLUG:
+      sm_event = BTA_HD_INT_VC_UNPLUG_EVT;
+      break;
+
+    case HID_DHOST_EVT_SUSPEND:
+      sm_event = BTA_HD_INT_SUSPEND_EVT;
+      break;
+
+    case HID_DHOST_EVT_EXIT_SUSPEND:
+      sm_event = BTA_HD_INT_EXIT_SUSPEND_EVT;
+      break;
+  }
+
+  if (sm_event != BTA_HD_INVALID_EVT &&
+      (p_buf = (tBTA_HD_CBACK_DATA*)osi_malloc(sizeof(tBTA_HD_CBACK_DATA) +
+                                               sizeof(BT_HDR))) != NULL) {
+    p_buf->hdr.event = sm_event;
+    bdcpy(p_buf->addr, bd_addr);
+    p_buf->data = data;
+    p_buf->p_data = pdata;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+#endif /* BTA_HD_INCLUDED */
diff --git a/bta/hd/bta_hd_api.cc b/bta/hd/bta_hd_api.cc
new file mode 100644
index 0000000..5ad73ba
--- /dev/null
+++ b/bta/hd/bta_hd_api.cc
@@ -0,0 +1,343 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 DEVICE API in the subsystem of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bta_hd_api.h"
+#include "bta_hd_int.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_hd_reg = {bta_hd_hdl_event, BTA_HdDisable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdEnable
+ *
+ * Description      Enables HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HdEnable(tBTA_HD_CBACK* p_cback) {
+  tBTA_HD_API_ENABLE* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_register(BTA_ID_HD, &bta_hd_reg);
+
+  p_buf = (tBTA_HD_API_ENABLE*)osi_malloc((uint16_t)sizeof(tBTA_HD_API_ENABLE));
+
+  if (p_buf != NULL) {
+    memset(p_buf, 0, sizeof(tBTA_HD_API_ENABLE));
+
+    p_buf->hdr.event = BTA_HD_API_ENABLE_EVT;
+    p_buf->p_cback = p_cback;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdDisable
+ *
+ * Description      Disables HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HdDisable(void) {
+  BT_HDR* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_deregister(BTA_ID_HD);
+
+  if ((p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR))) != NULL) {
+    p_buf->event = BTA_HD_API_DISABLE_EVT;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdRegisterApp
+ *
+ * Description      This function is called when application should be
+*registered
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO* p_app_info,
+                              tBTA_HD_QOS_INFO* p_in_qos,
+                              tBTA_HD_QOS_INFO* p_out_qos) {
+  tBTA_HD_REGISTER_APP* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (tBTA_HD_REGISTER_APP*)osi_malloc(
+           sizeof(tBTA_HD_REGISTER_APP))) != NULL) {
+    p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
+
+    if (p_app_info->p_name) {
+      strncpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
+      p_buf->name[BTA_HD_APP_NAME_LEN] = '\0';
+    } else {
+      p_buf->name[0] = '\0';
+    }
+
+    if (p_app_info->p_description) {
+      strncpy(p_buf->description, p_app_info->p_description,
+              BTA_HD_APP_DESCRIPTION_LEN);
+      p_buf->description[BTA_HD_APP_DESCRIPTION_LEN] = '\0';
+    } else {
+      p_buf->description[0] = '\0';
+    }
+
+    if (p_app_info->p_provider) {
+      strncpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
+      p_buf->provider[BTA_HD_APP_PROVIDER_LEN] = '\0';
+    } else {
+      p_buf->provider[0] = '\0';
+    }
+
+    p_buf->subclass = p_app_info->subclass;
+
+    p_buf->d_len = p_app_info->descriptor.dl_len;
+    memcpy(p_buf->d_data, p_app_info->descriptor.dsc_list,
+           p_app_info->descriptor.dl_len);
+
+    // copy qos data as-is
+    memcpy(&p_buf->in_qos, p_in_qos, sizeof(tBTA_HD_QOS_INFO));
+    memcpy(&p_buf->out_qos, p_out_qos, sizeof(tBTA_HD_QOS_INFO));
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdUnregisterApp
+ *
+ * Description      This function is called when application should be
+*unregistered
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdUnregisterApp(void) {
+  BT_HDR* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR))) != NULL) {
+    p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdSendReport
+ *
+ * Description      This function is called when report is to be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdSendReport(tBTA_HD_REPORT* p_report) {
+  tBTA_HD_SEND_REPORT* p_buf;
+
+  APPL_TRACE_VERBOSE("%s", __func__);
+
+  if (p_report->len > BTA_HD_REPORT_LEN) {
+    APPL_TRACE_WARNING(
+        "%s, report len (%d) > MTU len (%d), can't send report."
+        " Increase value of HID_DEV_MTU_SIZE to send larger reports",
+        __func__, p_report->len, BTA_HD_REPORT_LEN);
+    return;
+  }
+
+  if ((p_buf = (tBTA_HD_SEND_REPORT*)osi_malloc(sizeof(tBTA_HD_SEND_REPORT))) !=
+      NULL) {
+    p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT;
+
+    p_buf->use_intr = p_report->use_intr;
+    p_buf->type = p_report->type;
+    p_buf->id = p_report->id;
+    p_buf->len = p_report->len;
+    memcpy(p_buf->data, p_report->p_data, p_report->len);
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdVirtualCableUnplug
+ *
+ * Description      This function is called when VCU shall be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdVirtualCableUnplug(void) {
+  BT_HDR* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR))) != NULL) {
+    p_buf->event = BTA_HD_API_VC_UNPLUG_EVT;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdConnect
+ *
+ * Description      This function is called when connection to host shall be
+*made
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdConnect(void) {
+  BT_HDR* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR))) != NULL) {
+    p_buf->event = BTA_HD_API_CONNECT_EVT;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdDisconnect
+ *
+ * Description      This function is called when host shall be disconnected
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisconnect(void) {
+  BT_HDR* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR))) != NULL) {
+    p_buf->event = BTA_HD_API_DISCONNECT_EVT;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdAddDevice
+ *
+ * Description      This function is called when a device is virtually cabled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdAddDevice(BD_ADDR addr) {
+  tBTA_HD_DEVICE_CTRL* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) !=
+      NULL) {
+    p_buf->hdr.event = BTA_HD_API_ADD_DEVICE_EVT;
+
+    memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdRemoveDevice
+ *
+ * Description      This function is called when a device is virtually uncabled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdRemoveDevice(BD_ADDR addr) {
+  tBTA_HD_DEVICE_CTRL* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) !=
+      NULL) {
+    p_buf->hdr.event = BTA_HD_API_REMOVE_DEVICE_EVT;
+
+    memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdReportError
+ *
+ * Description      This function is called when reporting error for set report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdReportError(uint8_t error) {
+  tBTA_HD_REPORT_ERR* p_buf;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if ((p_buf = (tBTA_HD_REPORT_ERR*)osi_malloc(sizeof(tBTA_HD_REPORT_ERR))) !=
+      NULL) {
+    p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT;
+    p_buf->error = error;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+#endif /* BTA_HD_INCLUDED */
diff --git a/bta/hd/bta_hd_int.h b/bta/hd/bta_hd_int.h
new file mode 100644
index 0000000..d024709
--- /dev/null
+++ b/bta/hd/bta_hd_int.h
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 Device internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef BTA_HD_INT_H
+#define BTA_HD_INT_H
+
+#include "bta_hd_api.h"
+#include "bta_sys.h"
+#include "hiddefs.h"
+
+enum {
+  BTA_HD_API_REGISTER_APP_EVT = BTA_SYS_EVT_START(BTA_ID_HD),
+  BTA_HD_API_UNREGISTER_APP_EVT,
+  BTA_HD_API_CONNECT_EVT,
+  BTA_HD_API_DISCONNECT_EVT,
+  BTA_HD_API_ADD_DEVICE_EVT,
+  BTA_HD_API_REMOVE_DEVICE_EVT,
+  BTA_HD_API_SEND_REPORT_EVT,
+  BTA_HD_API_REPORT_ERROR_EVT,
+  BTA_HD_API_VC_UNPLUG_EVT,
+  BTA_HD_INT_OPEN_EVT,
+  BTA_HD_INT_CLOSE_EVT,
+  BTA_HD_INT_INTR_DATA_EVT,
+  BTA_HD_INT_GET_REPORT_EVT,
+  BTA_HD_INT_SET_REPORT_EVT,
+  BTA_HD_INT_SET_PROTOCOL_EVT,
+  BTA_HD_INT_VC_UNPLUG_EVT,
+  BTA_HD_INT_SUSPEND_EVT,
+  BTA_HD_INT_EXIT_SUSPEND_EVT,
+
+  /* handled outside state machine */
+  BTA_HD_API_ENABLE_EVT,
+  BTA_HD_API_DISABLE_EVT
+};
+typedef uint16_t tBTA_HD_INT_EVT;
+
+#define BTA_HD_INVALID_EVT (BTA_HD_API_DISABLE_EVT + 1)
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HD_CBACK* p_cback;
+} tBTA_HD_API_ENABLE;
+
+#define BTA_HD_APP_NAME_LEN 50
+#define BTA_HD_APP_DESCRIPTION_LEN 50
+#define BTA_HD_APP_PROVIDER_LEN 50
+#define BTA_HD_APP_DESCRIPTOR_LEN 2048
+
+#define BTA_HD_STATE_DISABLED 0x00
+#define BTA_HD_STATE_ENABLED 0x01
+#define BTA_HD_STATE_IDLE 0x02
+#define BTA_HD_STATE_CONNECTED 0x03
+#define BTA_HD_STATE_DISABLING 0x04
+#define BTA_HD_STATE_REMOVING 0x05
+
+typedef struct {
+  BT_HDR hdr;
+  char name[BTA_HD_APP_NAME_LEN + 1];
+  char description[BTA_HD_APP_DESCRIPTION_LEN + 1];
+  char provider[BTA_HD_APP_PROVIDER_LEN + 1];
+  uint8_t subclass;
+  uint16_t d_len;
+  uint8_t d_data[BTA_HD_APP_DESCRIPTOR_LEN];
+
+  tBTA_HD_QOS_INFO in_qos;
+  tBTA_HD_QOS_INFO out_qos;
+} tBTA_HD_REGISTER_APP;
+
+#define BTA_HD_REPORT_LEN HID_DEV_MTU_SIZE
+
+typedef struct {
+  BT_HDR hdr;
+  bool use_intr;
+  uint8_t type;
+  uint8_t id;
+  uint16_t len;
+  uint8_t data[BTA_HD_REPORT_LEN];
+} tBTA_HD_SEND_REPORT;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR addr;
+} tBTA_HD_DEVICE_CTRL;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t error;
+} tBTA_HD_REPORT_ERR;
+
+/* union of all event data types */
+typedef union {
+  BT_HDR hdr;
+  tBTA_HD_API_ENABLE api_enable;
+  tBTA_HD_REGISTER_APP register_app;
+  tBTA_HD_SEND_REPORT send_report;
+  tBTA_HD_DEVICE_CTRL device_ctrl;
+  tBTA_HD_REPORT_ERR report_err;
+} tBTA_HD_DATA;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR addr;
+  uint32_t data;
+  BT_HDR* p_data;
+} tBTA_HD_CBACK_DATA;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+typedef struct {
+  tBTA_HD_CBACK* p_cback;
+  uint32_t sdp_handle;
+  uint8_t trace_level;
+  uint8_t state;
+  BD_ADDR bd_addr;
+  bool use_report_id;
+  bool boot_mode;
+  bool vc_unplug;
+  bool disable_w4_close;
+} tBTA_HD_CB;
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HD_CB bta_hd_cb;
+#else
+extern tBTA_HD_CB* bta_hd_cb_ptr;
+#define bta_hd_cb (*bta_hd_cb_ptr)
+#endif
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+extern bool bta_hd_hdl_event(BT_HDR* p_msg);
+
+extern void bta_hd_api_enable(tBTA_HD_DATA* p_data);
+extern void bta_hd_api_disable(void);
+
+extern void bta_hd_register_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_unregister_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_unregister2_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_connect_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_disconnect_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_add_device_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_remove_device_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_send_report_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_report_error_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_vc_unplug_act(tBTA_HD_DATA* p_data);
+
+extern void bta_hd_open_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_close_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_intr_data_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_get_report_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_set_report_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_set_protocol_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_suspend_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_exit_suspend_act(tBTA_HD_DATA* p_data);
+
+#endif
diff --git a/bta/hd/bta_hd_main.cc b/bta/hd/bta_hd_main.cc
new file mode 100644
index 0000000..3e4fa57
--- /dev/null
+++ b/bta/hd/bta_hd_main.cc
@@ -0,0 +1,364 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hd_api.h"
+#include "bta_hd_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine states */
+enum {
+  BTA_HD_INIT_ST,
+  BTA_HD_IDLE_ST,              /* not connected, waiting for connection */
+  BTA_HD_CONN_ST,              /* host connected */
+  BTA_HD_TRANSIENT_TO_INIT_ST, /* transient state: going back from CONN to INIT
+                                  */
+};
+typedef uint8_t tBTA_HD_STATE;
+
+/* state machine actions */
+enum {
+  BTA_HD_REGISTER_ACT,
+  BTA_HD_UNREGISTER_ACT,
+  BTA_HD_UNREGISTER2_ACT,
+  BTA_HD_CONNECT_ACT,
+  BTA_HD_DISCONNECT_ACT,
+  BTA_HD_ADD_DEVICE_ACT,
+  BTA_HD_REMOVE_DEVICE_ACT,
+  BTA_HD_SEND_REPORT_ACT,
+  BTA_HD_REPORT_ERROR_ACT,
+  BTA_HD_VC_UNPLUG_ACT,
+
+  BTA_HD_OPEN_ACT,
+  BTA_HD_CLOSE_ACT,
+  BTA_HD_INTR_DATA_ACT,
+  BTA_HD_GET_REPORT_ACT,
+  BTA_HD_SET_REPORT_ACT,
+  BTA_HD_SET_PROTOCOL_ACT,
+  BTA_HD_VC_UNPLUG_DONE_ACT,
+  BTA_HD_SUSPEND_ACT,
+  BTA_HD_EXIT_SUSPEND_ACT,
+
+  BTA_HD_NUM_ACTIONS
+};
+
+#define BTA_HD_IGNORE BTA_HD_NUM_ACTIONS
+
+typedef void (*tBTA_HD_ACTION)(tBTA_HD_DATA* p_data);
+
+/* action functions */
+const tBTA_HD_ACTION bta_hd_action[] = {
+    bta_hd_register_act,       bta_hd_unregister_act,  bta_hd_unregister2_act,
+    bta_hd_connect_act,        bta_hd_disconnect_act,  bta_hd_add_device_act,
+    bta_hd_remove_device_act,  bta_hd_send_report_act, bta_hd_report_error_act,
+    bta_hd_vc_unplug_act,
+
+    bta_hd_open_act,           bta_hd_close_act,       bta_hd_intr_data_act,
+    bta_hd_get_report_act,     bta_hd_set_report_act,  bta_hd_set_protocol_act,
+    bta_hd_vc_unplug_done_act, bta_hd_suspend_act,     bta_hd_exit_suspend_act,
+};
+
+/* state table information */
+#define BTA_HD_ACTION 0     /* position of action */
+#define BTA_HD_NEXT_STATE 1 /* position of next state */
+#define BTA_HD_NUM_COLS 2   /* number of columns */
+
+const uint8_t bta_hd_st_init[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action                     Next state
+       */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_REGISTER_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+};
+
+const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action                     Next state
+       */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_UNREGISTER_ACT, BTA_HD_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_CONNECT_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+};
+
+const uint8_t bta_hd_st_conn[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action Next state */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_DISCONNECT_ACT,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_DISCONNECT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_REMOVE_DEVICE_ACT,
+                                         BTA_HD_CONN_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_SEND_REPORT_ACT,
+                                         BTA_HD_CONN_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_REPORT_ERROR_ACT,
+                                         BTA_HD_CONN_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_CLOSE_ACT, BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_INTR_DATA_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_GET_REPORT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_SET_REPORT_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_SET_PROTOCOL_ACT,
+                                         BTA_HD_CONN_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_VC_UNPLUG_DONE_ACT,
+                                         BTA_HD_IDLE_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_SUSPEND_ACT, BTA_HD_CONN_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_EXIT_SUSPEND_ACT,
+                                         BTA_HD_CONN_ST},
+};
+
+const uint8_t bta_hd_st_transient_to_init[][BTA_HD_NUM_COLS] = {
+    /* Event                               Action Next state */
+    /* BTA_HD_API_REGISTER_APP_EVT   */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_CONNECT_EVT        */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_DISCONNECT_EVT     */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_ADD_DEVICE_EVT     */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_REMOVE_DEVICE_EVT  */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_SEND_REPORT_EVT    */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_REPORT_ERROR_EVT   */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_API_VC_UNPLUG_EVT      */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_OPEN_EVT           */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_CLOSE_EVT          */ {BTA_HD_UNREGISTER2_ACT,
+                                         BTA_HD_INIT_ST},
+    /* BTA_HD_INT_INTR_DATA_EVT      */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_GET_REPORT_EVT     */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_SET_REPORT_EVT     */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_SET_PROTOCOL_EVT   */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_VC_UNPLUG_EVT      */ {BTA_HD_UNREGISTER2_ACT,
+                                         BTA_HD_INIT_ST},
+    /* BTA_HD_INT_SUSPEND_EVT        */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+    /* BTA_HD_INT_EXIT_SUSPEND_EVT   */ {BTA_HD_IGNORE,
+                                         BTA_HD_TRANSIENT_TO_INIT_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HD_ST_TBL)[BTA_HD_NUM_COLS];
+
+/* state table */
+const tBTA_HD_ST_TBL bta_hd_st_tbl[] = {bta_hd_st_init, bta_hd_st_idle,
+                                        bta_hd_st_conn,
+                                        bta_hd_st_transient_to_init};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HD_CB bta_hd_cb;
+#endif
+
+static const char* bta_hd_evt_code(tBTA_HD_INT_EVT evt_code);
+static const char* bta_hd_state_code(tBTA_HD_STATE state_code);
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_sm_execute
+ *
+ * Description      State machine event handling function for HID Device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hd_sm_execute(uint16_t event, tBTA_HD_DATA* p_data) {
+  tBTA_HD_ST_TBL state_table;
+  tBTA_HD_STATE prev_state;
+  uint8_t action;
+  tBTA_HD cback_data;
+
+  APPL_TRACE_EVENT("%s: state=%s (%d) event=%s (%d)", __func__,
+                   bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state,
+                   bta_hd_evt_code(event), event);
+
+  prev_state = bta_hd_cb.state;
+
+  memset(&cback_data, 0, sizeof(tBTA_HD));
+
+  state_table = bta_hd_st_tbl[bta_hd_cb.state];
+
+  event &= 0xff;
+
+  if ((action = state_table[event][BTA_HD_ACTION]) < BTA_HD_IGNORE) {
+    (*bta_hd_action[action])(p_data);
+  }
+
+  bta_hd_cb.state = state_table[event][BTA_HD_NEXT_STATE];
+
+  if (bta_hd_cb.state != prev_state) {
+    APPL_TRACE_EVENT("%s: [new] state=%s (%d)", __func__,
+                     bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state);
+  }
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hd_hdl_event
+ *
+ * Description      HID device main event handling function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_hd_hdl_event(BT_HDR* p_msg) {
+  APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event);
+
+  switch (p_msg->event) {
+    case BTA_HD_API_ENABLE_EVT:
+      bta_hd_api_enable((tBTA_HD_DATA*)p_msg);
+      break;
+
+    case BTA_HD_API_DISABLE_EVT:
+      if (bta_hd_cb.state == BTA_HD_CONN_ST) {
+        APPL_TRACE_WARNING("%s: host connected, disconnect before disabling",
+                           __func__);
+
+        // unregister (and disconnect)
+        bta_hd_cb.disable_w4_close = TRUE;
+        bta_hd_sm_execute(BTA_HD_API_UNREGISTER_APP_EVT, (tBTA_HD_DATA*)p_msg);
+      } else {
+        bta_hd_api_disable();
+      }
+      break;
+
+    default:
+      bta_hd_sm_execute(p_msg->event, (tBTA_HD_DATA*)p_msg);
+  }
+  return (TRUE);
+}
+
+static const char* bta_hd_evt_code(tBTA_HD_INT_EVT evt_code) {
+  switch (evt_code) {
+    case BTA_HD_API_REGISTER_APP_EVT:
+      return "BTA_HD_API_REGISTER_APP_EVT";
+    case BTA_HD_API_UNREGISTER_APP_EVT:
+      return "BTA_HD_API_UNREGISTER_APP_EVT";
+    case BTA_HD_API_CONNECT_EVT:
+      return "BTA_HD_API_CONNECT_EVT";
+    case BTA_HD_API_DISCONNECT_EVT:
+      return "BTA_HD_API_DISCONNECT_EVT";
+    case BTA_HD_API_ADD_DEVICE_EVT:
+      return "BTA_HD_API_ADD_DEVICE_EVT";
+    case BTA_HD_API_REMOVE_DEVICE_EVT:
+      return "BTA_HD_API_REMOVE_DEVICE_EVT";
+    case BTA_HD_API_SEND_REPORT_EVT:
+      return "BTA_HD_API_SEND_REPORT_EVT";
+    case BTA_HD_API_REPORT_ERROR_EVT:
+      return "BTA_HD_API_REPORT_ERROR_EVT";
+    case BTA_HD_API_VC_UNPLUG_EVT:
+      return "BTA_HD_API_VC_UNPLUG_EVT";
+    case BTA_HD_INT_OPEN_EVT:
+      return "BTA_HD_INT_OPEN_EVT";
+    case BTA_HD_INT_CLOSE_EVT:
+      return "BTA_HD_INT_CLOSE_EVT";
+    case BTA_HD_INT_INTR_DATA_EVT:
+      return "BTA_HD_INT_INTR_DATA_EVT";
+    case BTA_HD_INT_GET_REPORT_EVT:
+      return "BTA_HD_INT_GET_REPORT_EVT";
+    case BTA_HD_INT_SET_REPORT_EVT:
+      return "BTA_HD_INT_SET_REPORT_EVT";
+    case BTA_HD_INT_SET_PROTOCOL_EVT:
+      return "BTA_HD_INT_SET_PROTOCOL_EVT";
+    case BTA_HD_INT_VC_UNPLUG_EVT:
+      return "BTA_HD_INT_VC_UNPLUG_EVT";
+    case BTA_HD_INT_SUSPEND_EVT:
+      return "BTA_HD_INT_SUSPEND_EVT";
+    case BTA_HD_INT_EXIT_SUSPEND_EVT:
+      return "BTA_HD_INT_EXIT_SUSPEND_EVT";
+    default:
+      return "<unknown>";
+  }
+}
+
+static const char* bta_hd_state_code(tBTA_HD_STATE state_code) {
+  switch (state_code) {
+    case BTA_HD_INIT_ST:
+      return "BTA_HD_INIT_ST";
+    case BTA_HD_IDLE_ST:
+      return "BTA_HD_IDLE_ST";
+    case BTA_HD_CONN_ST:
+      return "BTA_HD_CONN_ST";
+    case BTA_HD_TRANSIENT_TO_INIT_ST:
+      return "BTA_HD_TRANSIENT_TO_INIT_ST";
+    default:
+      return "<unknown>";
+  }
+}
+
+#endif /* BTA_HD_INCLUDED */
diff --git a/bta/hh/bta_hh_utils.cc b/bta/hh/bta_hh_utils.cc
index 6f030fe..28dd2be 100644
--- a/bta/hh/bta_hh_utils.cc
+++ b/bta/hh/bta_hh_utils.cc
@@ -431,9 +431,11 @@
   }
   osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
 
-  (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
-  /* all connections are down, no waiting for diconnect */
-  memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+  if (bta_hh_cb.p_cback) {
+    (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
+    /* all connections are down, no waiting for diconnect */
+    memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+  }
 }
 
 /*******************************************************************************
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index c9c81ed..5de85ae 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -85,13 +85,14 @@
 #define BTA_MAP_SERVICE_ID 25        /* Message Access Profile */
 #define BTA_MN_SERVICE_ID 26         /* Message Notification Service */
 #define BTA_HDP_SERVICE_ID 27        /* Health Device Profile */
-#define BTA_PCE_SERVICE_ID 28        /* PhoneBook Access Client*/
-#define BTA_SDP_SERVICE_ID 29        /* SDP Search*/
+#define BTA_PCE_SERVICE_ID 28        /* PhoneBook Access Client */
+#define BTA_SDP_SERVICE_ID 29        /* SDP Search */
+#define BTA_HIDD_SERVICE_ID 30       /* HID Device */
 
 /* BLE profile service ID */
-#define BTA_BLE_SERVICE_ID 30  /* GATT profile */
-#define BTA_USER_SERVICE_ID 31 /* User requested UUID */
-#define BTA_MAX_SERVICE_ID 32
+#define BTA_BLE_SERVICE_ID 31  /* GATT profile */
+#define BTA_USER_SERVICE_ID 32 /* User requested UUID */
+#define BTA_MAX_SERVICE_ID 33
 
 /* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1)
  * are used by BTA JV */
@@ -130,10 +131,11 @@
 #define BTA_MN_SERVICE_MASK 0x04000000     /* Message Notification Profile */
 #define BTA_HL_SERVICE_MASK 0x08000000     /* Health Device Profile */
 #define BTA_PCE_SERVICE_MASK 0x10000000    /* Phone Book Client */
+#define BTA_HIDD_SERVICE_MASK 0x20000000   /* HID Device */
 
-#define BTA_BLE_SERVICE_MASK 0x20000000  /* GATT based service */
-#define BTA_ALL_SERVICE_MASK 0x3FFFFFFF  /* All services supported by BTA. */
-#define BTA_USER_SERVICE_MASK 0x40000000 /* Message Notification Profile */
+#define BTA_BLE_SERVICE_MASK 0x40000000  /* GATT based service */
+#define BTA_ALL_SERVICE_MASK 0x7FFFFFFF  /* All services supported by BTA. */
+#define BTA_USER_SERVICE_MASK 0x80000000 /* Message Notification Profile */
 
 typedef uint32_t tBTA_SERVICE_MASK;
 
@@ -1083,8 +1085,8 @@
 #endif
 
 #ifndef BTA_DM_PM_SNIFF2_MAX
-#define BTA_DM_PM_SNIFF2_MAX 180
-#define BTA_DM_PM_SNIFF2_MIN 150
+#define BTA_DM_PM_SNIFF2_MAX 54
+#define BTA_DM_PM_SNIFF2_MIN 30
 #define BTA_DM_PM_SNIFF2_ATTEMPT 4
 #define BTA_DM_PM_SNIFF2_TIMEOUT 1
 #endif
diff --git a/bta/include/bta_hd_api.h b/bta/include/bta_hd_api.h
new file mode 100644
index 0000000..a8314f6
--- /dev/null
+++ b/bta/include/bta_hd_api.h
@@ -0,0 +1,267 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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_HD_API_H
+#define BTA_HD_API_H
+
+#include "bta_api.h"
+#include "hidd_api.h"
+
+/*****************************************************************************
+ *  Constants and Type Definitions
+ ****************************************************************************/
+#ifndef BTA_HD_DEBUG
+#define BTA_HD_DEBUG FALSE
+#endif
+
+/* BTA HID Device callback events */
+#define BTA_HD_ENABLE_EVT 0         /* BT-HD enabled */
+#define BTA_HD_DISABLE_EVT 1        /* BT-HD disabled */
+#define BTA_HD_REGISTER_APP_EVT 2   /* application registered */
+#define BTA_HD_UNREGISTER_APP_EVT 3 /* application unregistered */
+#define BTA_HD_OPEN_EVT 4           /* connection to host opened */
+#define BTA_HD_CLOSE_EVT 5          /* connection to host closed */
+#define BTA_HD_GET_REPORT_EVT 6     /* GET_REPORT request from host */
+#define BTA_HD_SET_REPORT_EVT 7     /* SET_REPORT request from host */
+#define BTA_HD_SET_PROTOCOL_EVT 8   /* SET_PROTOCOL request from host */
+#define BTA_HD_INTR_DATA_EVT 9      /* DATA received from host on intr */
+#define BTA_HD_VC_UNPLUG_EVT 10     /* Virtual Cable Unplug */
+#define BTA_HD_API_ERR_EVT 99       /* BT-HD API error */
+
+typedef uint16_t tBTA_HD_EVT;
+
+enum { BTA_HD_OK, BTA_HD_ERROR };
+typedef uint8_t tBTA_HD_STATUS;
+
+typedef tHID_DEV_DSCP_INFO tBTA_HD_DEV_DESCR;
+
+typedef struct {
+  char* p_name;
+  char* p_description;
+  char* p_provider;
+  uint8_t subclass;
+  tBTA_HD_DEV_DESCR descriptor;
+} tBTA_HD_APP_INFO;
+
+typedef struct {
+  uint8_t service_type;
+  uint32_t token_rate;
+  uint32_t token_bucket_size;
+  uint32_t peak_bandwidth;
+  uint32_t access_latency;
+  uint32_t delay_variation;
+} tBTA_HD_QOS_INFO;
+
+typedef struct {
+  bool use_intr;
+  uint8_t type;
+  uint8_t id;
+  uint16_t len;
+  uint8_t* p_data;
+} tBTA_HD_REPORT;
+
+typedef struct {
+  tBTA_HD_STATUS status;
+  bool in_use;
+  BD_ADDR bda;
+} tBTA_HD_REG_STATUS;
+
+typedef struct {
+  BD_ADDR bda;
+  tBTA_HD_STATUS status;
+} tBTA_HD_CONN;
+
+typedef struct {
+  uint8_t report_type;
+  uint8_t report_id;
+  uint16_t buffer_size;
+} tBTA_HD_GET_REPORT;
+
+typedef struct {
+  uint8_t report_type;
+  uint8_t report_id;
+  uint16_t len;
+  uint8_t* p_data;
+} tBTA_HD_SET_REPORT;
+
+typedef uint8_t tBTA_HD_SET_PROTOCOL;
+
+typedef struct {
+  uint8_t report_id;
+  uint16_t len;
+  uint8_t* p_data;
+} tBTA_HD_INTR_DATA;
+
+/* union of data associated with HD callback */
+typedef union {
+  tBTA_HD_STATUS status;             /* BTA_HD_ENABLE_EVT
+                                        BTA_HD_DISABLE_EVT
+                                        BTA_HD_UNREGISTER_APP_EVT */
+  tBTA_HD_REG_STATUS reg_status;     /* BTA_HD_REGISTER_APP_EVT */
+  tBTA_HD_CONN conn;                 /* BTA_HD_OPEN_EVT
+                                        BTA_HD_CLOSE_EVT
+                                        BTA_HD_VC_UNPLUG_EVT
+                                        BTA_HD_OWN_VC_UNPLUG_EVT */
+  tBTA_HD_GET_REPORT get_report;     /* BTA_HD_GET_REPORT */
+  tBTA_HD_SET_REPORT set_report;     /* BTA_HD_SET_REPORT */
+  tBTA_HD_SET_PROTOCOL set_protocol; /* BTA_HD_SETPROTOCOL */
+  tBTA_HD_INTR_DATA intr_data;       /* BTA_HD_INTR_DATA_EVT */
+} tBTA_HD;
+
+/* BTA HD callback function */
+typedef void(tBTA_HD_CBACK)(tBTA_HD_EVT event, tBTA_HD* 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
+ *
+ ******************************************************************************/
+extern void BTA_HdEnable(tBTA_HD_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhDeregister
+ *
+ * Description      This function is called when the host is about power down.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdRegisterApp
+ *
+ * Description      This function is called when application should be
+*registered
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO* p_app_info,
+                              tBTA_HD_QOS_INFO* p_in_qos,
+                              tBTA_HD_QOS_INFO* p_out_qos);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdUnregisterApp
+ *
+ * Description      This function is called when application should be
+*unregistered
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdUnregisterApp(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdSendReport
+ *
+ * Description      This function is called when report is to be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdSendReport(tBTA_HD_REPORT* p_report);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdVirtualCableUnplug
+ *
+ * Description      This function is called when VCU shall be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdVirtualCableUnplug(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdConnect
+ *
+ * Description      This function is called when connection to host shall be
+*made
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdConnect(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdDisconnect
+ *
+ * Description      This function is called when host shall be disconnected
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisconnect(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdAddDevice
+ *
+ * Description      This function is called when a device is virtually cabled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdAddDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdRemoveDevice
+ *
+ * Description      This function is called when a device is virtually uncabled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdRemoveDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HdReportError
+ *
+ * Description      This function is called when reporting error for set report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HdReportError(uint8_t error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HD_API_H */
diff --git a/btif/Android.mk b/btif/Android.mk
index ba71a6f..3cca466 100644
--- a/btif/Android.mk
+++ b/btif/Android.mk
@@ -52,6 +52,7 @@
   src/btif_hf.cc \
   src/btif_hf_client.cc \
   src/btif_hh.cc \
+  src/btif_hd.cc \
   src/btif_hl.cc \
   src/btif_mce.cc \
   src/btif_pan.cc \
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index b3d9504..61a0614 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -42,6 +42,7 @@
     "src/btif_hf.cc",
     "src/btif_hf_client.cc",
     "src/btif_hh.cc",
+    "src/btif_hd.cc",
     "src/btif_hl.cc",
     "src/btif_mce.cc",
     "src/btif_pan.cc",
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index 2e3be58..797bd42 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -238,7 +238,7 @@
 }
 
 int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) {
-  APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len);
+  APPL_TRACE_VERBOSE("%s: UHID write %d", __func__, len);
 
   struct uhid_event ev;
   memset(&ev, 0, sizeof(ev));
diff --git a/btif/include/btif_hd.h b/btif/include/btif_hd.h
new file mode 100644
index 0000000..5697896
--- /dev/null
+++ b/btif/include/btif_hd.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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_HD_H
+#define BTIF_HD_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <stdint.h>
+#include "bta_hd_api.h"
+
+typedef enum {
+  BTIF_HD_DISABLED = 0,
+  BTIF_HD_ENABLED,
+  BTIF_HD_DISABLING
+} BTIF_HD_STATUS;
+
+/* BTIF-HD control block */
+typedef struct {
+  BTIF_HD_STATUS status;
+  bool app_registered;
+  bool service_dereg_active;
+  bool forced_disc;
+} btif_hd_cb_t;
+
+extern btif_hd_cb_t btif_hd_cb;
+
+extern void btif_hd_remove_device(bt_bdaddr_t bd_addr);
+extern void btif_hd_service_registration();
+
+#endif
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index 3b35304..95ab382 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -87,6 +87,7 @@
   uint32_t device_num;
   btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
   btif_hh_device_t* p_curr_dev;
+  bool service_dereg_active;
 } btif_hh_cb_t;
 
 /*******************************************************************************
@@ -103,6 +104,7 @@
 extern void btif_hh_setreport(btif_hh_device_t* p_dev,
                               bthh_report_type_t r_type, uint16_t size,
                               uint8_t* report);
+extern void btif_hh_service_registration(bool enable);
 
 bool btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
 
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index a2b0959..dc7f4cc 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -227,6 +227,40 @@
 bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
                                               uint8_t addr_type);
 
+/*******************************************************************************
+ * Function         btif_storage_load_hidd
+ *
+ * Description      Loads hidd bonded device and "plugs" it into hidd
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_hidd(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_hidd
+ *
+ * Description      Stores hidd bonded device info in nvram.
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_set_hidd(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_hidd
+ *
+ * Description      Removes hidd bonded device info from nvram
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_remove_hidd(bt_bdaddr_t* remote_bd_addr);
+
 /******************************************************************************
  * Exported for unit tests
  *****************************************************************************/
diff --git a/btif/include/btif_util.h b/btif/include/btif_util.h
index 5dba43c..a1a6492 100644
--- a/btif/include/btif_util.h
+++ b/btif/include/btif_util.h
@@ -50,6 +50,7 @@
 const char* dump_hf_event(uint16_t event);
 const char* dump_hf_client_event(uint16_t event);
 const char* dump_hh_event(uint16_t event);
+const char* dump_hd_event(uint16_t event);
 const char* dump_hf_conn_state(uint16_t event);
 const char* dump_hf_call_state(bthf_call_state_t call_state);
 const char* dump_property_type(bt_property_type_t type);
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 8594d25..bc9ec57 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -35,6 +35,7 @@
 #include <hardware/bluetooth.h>
 #include <hardware/bt_av.h>
 #include <hardware/bt_gatt.h>
+#include <hardware/bt_hd.h>
 #include <hardware/bt_hf.h>
 #include <hardware/bt_hf_client.h>
 #include <hardware/bt_hh.h>
@@ -89,6 +90,8 @@
 extern btsock_interface_t* btif_sock_get_interface();
 /* hid host profile */
 extern bthh_interface_t* btif_hh_get_interface();
+/* hid device profile */
+extern bthd_interface_t* btif_hd_get_interface();
 /* health device profile */
 extern bthl_interface_t* btif_hl_get_interface();
 /*pan*/
@@ -315,7 +318,7 @@
 }
 
 static const void* get_profile_interface(const char* profile_id) {
-  LOG_INFO(LOG_TAG, "get_profile_interface %s", profile_id);
+  LOG_INFO(LOG_TAG, "%s: id = %s", __func__, profile_id);
 
   /* sanity check */
   if (interface_ready() == false) return NULL;
@@ -342,6 +345,9 @@
   if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
     return btif_hh_get_interface();
 
+  if (is_profile(profile_id, BT_PROFILE_HIDDEV_ID))
+    return btif_hd_get_interface();
+
   if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
     return btif_hl_get_interface();
 
@@ -361,7 +367,7 @@
 }
 
 int dut_mode_configure(uint8_t enable) {
-  LOG_INFO(LOG_TAG, "dut_mode_configure");
+  LOG_INFO(LOG_TAG, "%s", __func__);
 
   /* sanity check */
   if (interface_ready() == false) return BT_STATUS_NOT_READY;
@@ -370,7 +376,7 @@
 }
 
 int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
-  LOG_INFO(LOG_TAG, "dut_mode_send");
+  LOG_INFO(LOG_TAG, "%s", __func__);
 
   /* sanity check */
   if (interface_ready() == false) return BT_STATUS_NOT_READY;
@@ -379,7 +385,7 @@
 }
 
 int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
-  LOG_INFO(LOG_TAG, "le_test_mode");
+  LOG_INFO(LOG_TAG, "%s", __func__);
 
   /* sanity check */
   if (interface_ready() == false) return BT_STATUS_NOT_READY;
@@ -388,7 +394,7 @@
 }
 
 int config_hci_snoop_log(uint8_t enable) {
-  LOG_INFO(LOG_TAG, "config_hci_snoop_log");
+  LOG_INFO(LOG_TAG, "%s", __func__);
 
   if (!interface_ready()) return BT_STATUS_NOT_READY;
 
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index 3ee2604..15fcaf0 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -47,9 +47,14 @@
 #include "bta_gatt_api.h"
 #include "btif_api.h"
 #include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_hd.h"
+#include "btif_hh.h"
 #include "btif_hh.h"
 #include "btif_sdp.h"
 #include "btif_storage.h"
+#include "btif_storage.h"
+#include "btif_util.h"
 #include "btif_util.h"
 #include "btu.h"
 #include "device/include/interop.h"
@@ -247,6 +252,7 @@
 extern void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
                                                uint16_t uuid_16);
 extern void btif_av_move_idle(bt_bdaddr_t bd_addr);
+extern bt_status_t btif_hd_execute_service(bool b_enable);
 
 /******************************************************************************
  *  Functions
@@ -313,6 +319,9 @@
     case BTA_SDP_SERVICE_ID: {
       btif_sdp_execute_service(b_enable);
     } break;
+    case BTA_HIDD_SERVICE_ID: {
+      btif_hd_execute_service(b_enable);
+    } break;
     default:
       BTIF_TRACE_ERROR("%s: Unknown service %d being %s", __func__, service_id,
                        (b_enable) ? "enabled" : "disabled");
@@ -1669,6 +1678,9 @@
 #if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == true))
       btif_hh_remove_device(bd_addr);
 #endif
+#if (defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE))
+      btif_hd_remove_device(bd_addr);
+#endif
       btif_storage_remove_bonded_device(&bd_addr);
       bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
       break;
diff --git a/btif/src/btif_hd.cc b/btif/src/btif_hd.cc
new file mode 100644
index 0000000..3c7aa9a
--- /dev/null
+++ b/btif/src/btif_hd.cc
@@ -0,0 +1,676 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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_hd.c
+ *
+ *  Description:   HID Device Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "BTIF_HD"
+
+#include "bta_api.h"
+#include "bta_hd_api.h"
+#include "bta_hh_api.h"
+
+#include "btif_common.h"
+#include "btif_hd.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+
+#define BTIF_HD_APP_NAME_LEN 50
+#define BTIF_HD_APP_DESCRIPTION_LEN 50
+#define BTIF_HD_APP_PROVIDER_LEN 50
+#define BTIF_HD_APP_DESCRIPTOR_LEN 2048
+
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+#define COD_HID_MAJOR 0x0500
+
+extern bool bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr);
+extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
+extern void btif_hh_service_registration(bool enable);
+
+/* HD request events */
+typedef enum { BTIF_HD_DUMMY_REQ_EVT = 0 } btif_hd_req_evt_t;
+
+btif_hd_cb_t btif_hd_cb;
+
+static bthd_callbacks_t* bt_hd_callbacks = NULL;
+static tBTA_HD_APP_INFO app_info;
+static tBTA_HD_QOS_INFO in_qos;
+static tBTA_HD_QOS_INFO out_qos;
+
+static void intr_data_copy_cb(uint16_t event, char* p_dst, char* p_src) {
+  tBTA_HD_INTR_DATA* p_dst_data = (tBTA_HD_INTR_DATA*)p_dst;
+  tBTA_HD_INTR_DATA* p_src_data = (tBTA_HD_INTR_DATA*)p_src;
+  uint8_t* p_data;
+
+  if (!p_src) return;
+
+  if (event != BTA_HD_INTR_DATA_EVT) return;
+
+  memcpy(p_dst, p_src, sizeof(tBTA_HD_INTR_DATA));
+
+  p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_INTR_DATA);
+
+  memcpy(p_data, p_src_data->p_data, p_src_data->len);
+
+  p_dst_data->p_data = p_data;
+}
+
+static void set_report_copy_cb(uint16_t event, char* p_dst, char* p_src) {
+  tBTA_HD_SET_REPORT* p_dst_data = (tBTA_HD_SET_REPORT*)p_dst;
+  tBTA_HD_SET_REPORT* p_src_data = (tBTA_HD_SET_REPORT*)p_src;
+  uint8_t* p_data;
+
+  if (!p_src) return;
+
+  if (event != BTA_HD_SET_REPORT_EVT) return;
+
+  memcpy(p_dst, p_src, sizeof(tBTA_HD_SET_REPORT));
+
+  p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_SET_REPORT);
+
+  memcpy(p_data, p_src_data->p_data, p_src_data->len);
+
+  p_dst_data->p_data = p_data;
+}
+
+static void btif_hd_free_buf() {
+  if (app_info.descriptor.dsc_list) osi_free(app_info.descriptor.dsc_list);
+  if (app_info.p_description) osi_free(app_info.p_description);
+  if (app_info.p_name) osi_free(app_info.p_name);
+  if (app_info.p_provider) osi_free(app_info.p_provider);
+  app_info.descriptor.dsc_list = NULL;
+  app_info.p_description = NULL;
+  app_info.p_name = NULL;
+  app_info.p_provider = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hd_remove_device
+ *
+ * Description      Removes plugged device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_hd_remove_device(bt_bdaddr_t bd_addr) {
+  BTA_HdRemoveDevice((uint8_t*)&bd_addr);
+  btif_storage_remove_hidd(&bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hd_upstreams_evt
+ *
+ * Description      Executes events in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hd_upstreams_evt(uint16_t event, char* p_param) {
+  tBTA_HD* p_data = (tBTA_HD*)p_param;
+
+  BTIF_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
+
+  switch (event) {
+    case BTA_HD_ENABLE_EVT:
+      BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
+      if (p_data->status == BTA_HD_OK) {
+        btif_storage_load_hidd();
+        btif_hd_cb.status = BTIF_HD_ENABLED;
+        /* Register the app if not yet registered */
+        if (!btif_hd_cb.app_registered) {
+          BTA_HdRegisterApp(&app_info, &in_qos, &out_qos);
+          btif_hd_free_buf();
+        }
+      } else {
+        btif_hd_cb.status = BTIF_HD_DISABLED;
+        BTIF_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
+      }
+      break;
+
+    case BTA_HD_DISABLE_EVT:
+      BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
+      btif_hd_cb.status = BTIF_HD_DISABLED;
+      if (btif_hd_cb.service_dereg_active) {
+        BTIF_TRACE_WARNING("registering hid host now");
+        btif_hh_service_registration(TRUE);
+        btif_hd_cb.service_dereg_active = FALSE;
+      }
+      btif_hd_free_buf();
+      if (p_data->status == BTA_HD_OK)
+        memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
+      else
+        BTIF_TRACE_WARNING("Failed to disable BT-HD, status=%d",
+                           p_data->status);
+      break;
+
+    case BTA_HD_REGISTER_APP_EVT: {
+      bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->reg_status.bda;
+
+      if (!p_data->reg_status.in_use) {
+        addr = NULL;
+      }
+
+      btif_hd_cb.app_registered = TRUE;
+      HAL_CBACK(bt_hd_callbacks, application_state_cb, addr,
+                BTHD_APP_STATE_REGISTERED);
+    } break;
+
+    case BTA_HD_UNREGISTER_APP_EVT:
+      btif_hd_cb.app_registered = FALSE;
+      HAL_CBACK(bt_hd_callbacks, application_state_cb, NULL,
+                BTHD_APP_STATE_NOT_REGISTERED);
+      if (btif_hd_cb.service_dereg_active) {
+        BTIF_TRACE_WARNING("disabling hid device service now");
+        btif_hd_free_buf();
+        BTA_HdDisable();
+      }
+      break;
+
+    case BTA_HD_OPEN_EVT: {
+      bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->conn.bda;
+      BTIF_TRACE_WARNING(
+          "BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)",
+          addr->address[0], addr->address[1], addr->address[2],
+          addr->address[3], addr->address[4], addr->address[5]);
+      /* Check if the connection is from hid host and not hid device */
+      if (check_cod_hid(addr)) {
+        /* Incoming connection from hid device, reject it */
+        BTIF_TRACE_WARNING("remote device is not hid host, disconnecting");
+        btif_hd_cb.forced_disc = TRUE;
+        BTA_HdDisconnect();
+        break;
+      }
+      btif_storage_set_hidd((bt_bdaddr_t*)&p_data->conn.bda);
+
+      HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+                (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_CONNECTED);
+    } break;
+
+    case BTA_HD_CLOSE_EVT:
+      if (btif_hd_cb.forced_disc) {
+        bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->conn.bda;
+        BTIF_TRACE_WARNING("remote device was forcefully disconnected");
+        btif_hd_remove_device(*addr);
+        btif_hd_cb.forced_disc = FALSE;
+        break;
+      }
+      HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+                (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED);
+      break;
+
+    case BTA_HD_GET_REPORT_EVT:
+      HAL_CBACK(bt_hd_callbacks, get_report_cb, p_data->get_report.report_type,
+                p_data->get_report.report_id, p_data->get_report.buffer_size);
+      break;
+
+    case BTA_HD_SET_REPORT_EVT:
+      HAL_CBACK(bt_hd_callbacks, set_report_cb, p_data->set_report.report_type,
+                p_data->set_report.report_id, p_data->set_report.len,
+                p_data->set_report.p_data);
+      break;
+
+    case BTA_HD_SET_PROTOCOL_EVT:
+      HAL_CBACK(bt_hd_callbacks, set_protocol_cb, p_data->set_protocol);
+      break;
+
+    case BTA_HD_INTR_DATA_EVT:
+      HAL_CBACK(bt_hd_callbacks, intr_data_cb, p_data->intr_data.report_id,
+                p_data->intr_data.len, p_data->intr_data.p_data);
+      break;
+
+    case BTA_HD_VC_UNPLUG_EVT:
+      HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+                (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED);
+      if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
+        BTIF_TRACE_DEBUG("%s: Removing bonding as only HID profile connected",
+                         __func__);
+        BTA_DmRemoveDevice((uint8_t*)&p_data->conn.bda);
+      } else {
+        bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)&p_data->conn.bda;
+        BTIF_TRACE_DEBUG(
+            "%s: Only removing HID data as some other profiles "
+            "connected",
+            __func__);
+        btif_hd_remove_device(*bd_addr);
+      }
+      HAL_CBACK(bt_hd_callbacks, vc_unplug_cb);
+      break;
+
+    default:
+      BTIF_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_hd_evt
+ *
+ * Description      Switches context from BTE to BTIF for all BT-HD events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD* p_data) {
+  bt_status_t status;
+  int param_len = 0;
+  tBTIF_COPY_CBACK* p_copy_cback = NULL;
+
+  BTIF_TRACE_API("%s event=%d", __func__, event);
+
+  switch (event) {
+    case BTA_HD_ENABLE_EVT:
+    case BTA_HD_DISABLE_EVT:
+    case BTA_HD_UNREGISTER_APP_EVT:
+      param_len = sizeof(tBTA_HD_STATUS);
+      break;
+
+    case BTA_HD_REGISTER_APP_EVT:
+      param_len = sizeof(tBTA_HD_REG_STATUS);
+      break;
+
+    case BTA_HD_OPEN_EVT:
+    case BTA_HD_CLOSE_EVT:
+    case BTA_HD_VC_UNPLUG_EVT:
+      param_len = sizeof(tBTA_HD_CONN);
+      break;
+
+    case BTA_HD_GET_REPORT_EVT:
+      param_len += sizeof(tBTA_HD_GET_REPORT);
+      break;
+
+    case BTA_HD_SET_REPORT_EVT:
+      param_len = sizeof(tBTA_HD_SET_REPORT) + p_data->set_report.len;
+      p_copy_cback = set_report_copy_cb;
+      break;
+
+    case BTA_HD_SET_PROTOCOL_EVT:
+      param_len += sizeof(p_data->set_protocol);
+      break;
+
+    case BTA_HD_INTR_DATA_EVT:
+      param_len = sizeof(tBTA_HD_INTR_DATA) + p_data->intr_data.len;
+      p_copy_cback = intr_data_copy_cb;
+      break;
+  }
+
+  status = btif_transfer_context(btif_hd_upstreams_evt, (uint16_t)event,
+                                 (char*)p_data, param_len, p_copy_cback);
+
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function        init
+ *
+ * Description     Initializes BT-HD interface
+ *
+ * Returns         BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+static bt_status_t init(bthd_callbacks_t* callbacks) {
+  BTIF_TRACE_API("%s", __func__);
+
+  bt_hd_callbacks = callbacks;
+  memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
+
+  btif_enable_service(BTA_HIDD_SERVICE_ID);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Cleans up BT-HD interface
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+  BTIF_TRACE_API("hd:%s", __func__);
+
+  if (bt_hd_callbacks) {
+    /* update flag, not to enable hid host service now as BT is switching off */
+    btif_hd_cb.service_dereg_active = FALSE;
+    btif_disable_service(BTA_HIDD_SERVICE_ID);
+    bt_hd_callbacks = NULL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         register_app
+ *
+ * Description      Registers HID Device application
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t register_app(bthd_app_param_t* p_app_param,
+                                bthd_qos_param_t* p_in_qos,
+                                bthd_qos_param_t* p_out_qos) {
+  BTIF_TRACE_API("%s", __func__);
+
+  if (btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application already registered", __func__);
+    return BT_STATUS_BUSY;
+  }
+
+  app_info.p_name = (char*)osi_malloc(BTIF_HD_APP_NAME_LEN);
+  memcpy(app_info.p_name, p_app_param->name, BTIF_HD_APP_NAME_LEN);
+  app_info.p_description = (char*)osi_malloc(BTIF_HD_APP_DESCRIPTION_LEN);
+  memcpy(app_info.p_description, p_app_param->description,
+         BTIF_HD_APP_DESCRIPTION_LEN);
+  app_info.p_provider = (char*)osi_malloc(BTIF_HD_APP_PROVIDER_LEN);
+  memcpy(app_info.p_provider, p_app_param->provider, BTIF_HD_APP_PROVIDER_LEN);
+  app_info.subclass = p_app_param->subclass;
+  app_info.descriptor.dl_len = p_app_param->desc_list_len;
+  app_info.descriptor.dsc_list =
+      (uint8_t*)osi_malloc(app_info.descriptor.dl_len);
+  memcpy(app_info.descriptor.dsc_list, p_app_param->desc_list,
+         p_app_param->desc_list_len);
+
+  in_qos.service_type = p_in_qos->service_type;
+  in_qos.token_rate = p_in_qos->token_rate;
+  in_qos.token_bucket_size = p_in_qos->token_bucket_size;
+  in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
+  in_qos.access_latency = p_in_qos->access_latency;
+  in_qos.delay_variation = p_in_qos->delay_variation;
+
+  out_qos.service_type = p_out_qos->service_type;
+  out_qos.token_rate = p_out_qos->token_rate;
+  out_qos.token_bucket_size = p_out_qos->token_bucket_size;
+  out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
+  out_qos.access_latency = p_out_qos->access_latency;
+  out_qos.delay_variation = p_out_qos->delay_variation;
+
+  /* register HID Device with L2CAP and unregister HID Host with L2CAP */
+  /* Disable HH */
+  btif_hh_service_registration(FALSE);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         unregister_app
+ *
+ * Description      Unregisters HID Device application
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t unregister_app(void) {
+  BTIF_TRACE_API("%s", __func__);
+
+  if (!btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+    BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+                       btif_hd_cb.status);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.service_dereg_active) {
+    BTIF_TRACE_WARNING("%s: BT-HD deregistering in progress", __func__);
+    return BT_STATUS_BUSY;
+  }
+
+  btif_hd_cb.service_dereg_active = TRUE;
+  BTA_HdUnregisterApp();
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         connect
+ *
+ * Description      Connects to host
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect(void) {
+  BTIF_TRACE_API("%s", __func__);
+
+  if (!btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+    BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+                       btif_hd_cb.status);
+    return BT_STATUS_NOT_READY;
+  }
+
+  BTA_HdConnect();
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect
+ *
+ * Description      Disconnects from host
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(void) {
+  BTIF_TRACE_API("%s", __func__);
+
+  if (!btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+    BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+                       btif_hd_cb.status);
+    return BT_STATUS_NOT_READY;
+  }
+
+  BTA_HdDisconnect();
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         send_report
+ *
+ * Description      Sends Reports to hid host
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_report(bthd_report_type_t type, uint8_t id,
+                               uint16_t len, uint8_t* p_data) {
+  tBTA_HD_REPORT report;
+
+  APPL_TRACE_VERBOSE("%s: type=%d id=%d len=%d", __func__, type, id, len);
+
+  if (!btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+    BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+                       btif_hd_cb.status);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (type == BTHD_REPORT_TYPE_INTRDATA) {
+    report.type = BTHD_REPORT_TYPE_INPUT;
+    report.use_intr = TRUE;
+  } else {
+    report.type = (type & 0x03);
+    report.use_intr = FALSE;
+  }
+
+  report.id = id;
+  report.len = len;
+  report.p_data = p_data;
+
+  BTA_HdSendReport(&report);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         report_error
+ *
+ * Description      Sends HANDSHAKE with error info for invalid SET_REPORT
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t report_error(uint8_t error) {
+  BTIF_TRACE_API("%s", __func__);
+
+  if (!btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+    BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+                       btif_hd_cb.status);
+    return BT_STATUS_NOT_READY;
+  }
+
+  BTA_HdReportError(error);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         virtual_cable_unplug
+ *
+ * Description      Sends Virtual Cable Unplug to host
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t virtual_cable_unplug(void) {
+  BTIF_TRACE_API("%s", __func__);
+
+  if (!btif_hd_cb.app_registered) {
+    BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+
+  if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+    BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+                       btif_hd_cb.status);
+    return BT_STATUS_NOT_READY;
+  }
+
+  BTA_HdVirtualCableUnplug();
+
+  return BT_STATUS_SUCCESS;
+}
+
+static const bthd_interface_t bthdInterface = {
+    sizeof(bthdInterface),
+    init,
+    cleanup,
+    register_app,
+    unregister_app,
+    connect,
+    disconnect,
+    send_report,
+    report_error,
+    virtual_cable_unplug,
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_hd_execute_service
+ *
+ * Description      Enabled/disables BT-HD service
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_hd_execute_service(bool b_enable) {
+  BTIF_TRACE_API("%s: b_enable=%d", __func__, b_enable);
+
+  if (!b_enable) BTA_HdDisable();
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hd_get_interface
+ *
+ * Description      Gets BT-HD interface
+ *
+ * Returns          bthd_interface_t
+ *
+ ******************************************************************************/
+const bthd_interface_t* btif_hd_get_interface() {
+  BTIF_TRACE_API("%s", __func__);
+  return &bthdInterface;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hd_service_registration
+ *
+ * Description      Registers hid device service
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+void btif_hd_service_registration() {
+  BTIF_TRACE_API("%s", __func__);
+  /* enable HD */
+  BTA_HdEnable(bte_hd_evt);
+}
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index bfb4dae..2bd0d69 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -150,6 +150,7 @@
 extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
 extern int scru_ascii_2_hex(char* p_ascii, int len, uint8_t* p_hex);
 extern void btif_dm_hh_open_failed(bt_bdaddr_t* bdaddr);
+extern void btif_hd_service_registration();
 
 /*****************************************************************************
  *  Local Function prototypes
@@ -159,6 +160,7 @@
 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_timer_timeout(void* data);
+void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data);
 
 /*******************************************************************************
  *  Functions
@@ -672,6 +674,27 @@
   BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
 }
 
+/*******************************************************************************
+ *
+ * Function         btif_hh_service_registration
+ *
+ * Description      Registers or derigisters the hid host service
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+void btif_hh_service_registration(bool enable) {
+  BTIF_TRACE_API("%s", __func__);
+
+  BTIF_TRACE_API("enable = %d", enable);
+  if (enable) {
+    BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt);
+  } else {
+    btif_hh_cb.service_dereg_active = TRUE;
+    BTA_HhDisable();
+  }
+}
+
 /*****************************************************************************
  *   Section name (Group of functions)
  ****************************************************************************/
@@ -697,7 +720,8 @@
   int i;
   int len, tmplen;
 
-  BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_hh_event(event));
+  BTIF_TRACE_DEBUG("%s: event=%s dereg = %d", __func__, dump_hh_event(event),
+                   btif_hh_cb.service_dereg_active);
 
   switch (event) {
     case BTA_HH_ENABLE_EVT:
@@ -718,6 +742,11 @@
 
     case BTA_HH_DISABLE_EVT:
       btif_hh_cb.status = BTIF_HH_DISABLED;
+      if (btif_hh_cb.service_dereg_active) {
+        BTIF_TRACE_DEBUG("BTA_HH_DISABLE_EVT: enabling HID Device service");
+        btif_hd_service_registration();
+        btif_hh_cb.service_dereg_active = FALSE;
+      }
       if (p_data->status == BTA_HH_OK) {
         int i;
         // Clear the control block
@@ -1080,7 +1109,7 @@
  *
  ******************************************************************************/
 
-static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
+void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
   bt_status_t status;
   int param_len = 0;
 
@@ -1592,7 +1621,14 @@
                        __func__, btif_hh_cb.status);
     return;
   }
-  btif_hh_cb.status = BTIF_HH_DISABLING;
+  if (bt_hh_callbacks) {
+    btif_hh_cb.status = BTIF_HH_DISABLING;
+    /* update flag, not to enable hid device service now as BT is switching off
+     */
+    btif_hh_cb.service_dereg_active = FALSE;
+    btif_disable_service(BTA_HID_SERVICE_ID);
+    bt_hh_callbacks = NULL;
+  }
   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) {
@@ -1606,10 +1642,6 @@
     }
   }
 
-  if (bt_hh_callbacks) {
-    btif_disable_service(BTA_HID_SERVICE_ID);
-    bt_hh_callbacks = NULL;
-  }
 }
 
 static const bthh_interface_t bthhInterface = {
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index c79272c..04b10f8 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -39,11 +39,14 @@
 #include <string.h>
 #include <time.h>
 
+#include <cutils/log.h>
 #include "bt_common.h"
+#include "bta_hd_api.h"
 #include "bta_hh_api.h"
 #include "btcore/include/bdaddr.h"
 #include "btif_api.h"
 #include "btif_config.h"
+#include "btif_hd.h"
 #include "btif_hh.h"
 #include "btif_util.h"
 #include "osi/include/allocator.h"
@@ -1349,3 +1352,70 @@
 
   return btif_config_exist(bdstr, "Restricted");
 }
+
+/*******************************************************************************
+ * Function         btif_storage_load_hidd
+ *
+ * Description      Loads hidd bonded device and "plugs" it into hidd
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_hidd(void) {
+  bt_bdaddr_t bd_addr;
+
+  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+       iter != btif_config_section_end();
+       iter = btif_config_section_next(iter)) {
+    const char* name = btif_config_section_name(iter);
+    if (!string_is_bdaddr(name)) continue;
+
+    BTIF_TRACE_DEBUG("Remote device:%s", name);
+    int value;
+    if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
+      if (btif_config_get_int(name, "HidDeviceCabled", &value)) {
+        string_to_bdaddr(name, &bd_addr);
+        BTA_HdAddDevice(bd_addr.address);
+        break;
+      }
+    }
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_hidd
+ *
+ * Description      Stores hidd bonded device info in nvram.
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_hidd(bt_bdaddr_t* remote_bd_addr) {
+  bdstr_t bdstr = {0};
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  btif_config_set_int(bdstr, "HidDeviceCabled", 1);
+  btif_config_save();
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_hidd
+ *
+ * Description      Removes hidd bonded device info from nvram
+ *
+ * Returns          BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hidd(bt_bdaddr_t* remote_bd_addr) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+  btif_config_remove(bdstr, "HidDeviceCabled");
+  btif_config_save();
+
+  return BT_STATUS_SUCCESS;
+}
diff --git a/btif/src/btif_util.cc b/btif/src/btif_util.cc
index d268a2d..7ebdb37 100644
--- a/btif/src/btif_util.cc
+++ b/btif/src/btif_util.cc
@@ -44,6 +44,7 @@
 #include "bta_ag_api.h"
 #include "bta_api.h"
 #include "bta_av_api.h"
+#include "bta_hd_api.h"
 #include "bta_hf_client_api.h"
 #include "bta_hh_api.h"
 #include "bte.h"
@@ -362,6 +363,25 @@
   }
 }
 
+const char* dump_hd_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_HD_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_HD_DISABLE_EVT)
+    CASE_RETURN_STR(BTA_HD_REGISTER_APP_EVT)
+    CASE_RETURN_STR(BTA_HD_UNREGISTER_APP_EVT)
+    CASE_RETURN_STR(BTA_HD_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HD_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HD_GET_REPORT_EVT)
+    CASE_RETURN_STR(BTA_HD_SET_REPORT_EVT)
+    CASE_RETURN_STR(BTA_HD_SET_PROTOCOL_EVT)
+    CASE_RETURN_STR(BTA_HD_INTR_DATA_EVT)
+    CASE_RETURN_STR(BTA_HD_VC_UNPLUG_EVT)
+    CASE_RETURN_STR(BTA_HD_API_ERR_EVT)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
 const char* dump_hf_call_state(bthf_call_state_t call_state) {
   switch (call_state) {
     CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index 6654943..a89b243 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -39,6 +39,8 @@
 TRC_GAP=2
 TRC_BNEP=2
 TRC_PAN=2
+TRC_HID_HOST=2
+TRC_HID_DEV=2
 
 # This is Log configuration for new C++ code using LOG() macros.
 # See libchrome/base/logging.h for description on how to configure your logs.
diff --git a/include/bt_target.h b/include/bt_target.h
index ce6f5c4..bb42b93 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -59,6 +59,10 @@
 #define BTA_PAN_INCLUDED TRUE
 #endif
 
+#ifndef BTA_HD_INCLUDED
+#define BTA_HD_INCLUDED TRUE
+#endif
+
 #ifndef BTA_HH_INCLUDED
 #define BTA_HH_INCLUDED TRUE
 #endif
@@ -1245,6 +1249,15 @@
  *
  *****************************************************************************/
 
+/* HID Device Role Included */
+#ifndef HID_DEV_INCLUDED
+#define HID_DEV_INCLUDED TRUE
+#endif
+
+#ifndef HID_DEV_SUBCLASS
+#define HID_DEV_SUBCLASS COD_MINOR_POINTING
+#endif
+
 #ifndef HID_CONTROL_BUF_SIZE
 #define HID_CONTROL_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
 #endif
@@ -1253,6 +1266,14 @@
 #define HID_INTERRUPT_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
 #endif
 
+#ifndef HID_DEV_MTU_SIZE
+#define HID_DEV_MTU_SIZE 64
+#endif
+
+#ifndef HID_DEV_FLUSH_TO
+#define HID_DEV_FLUSH_TO 0xffff
+#endif
+
 /*************************************************************************
  * Definitions for Both HID-Host & Device
 */
diff --git a/include/bt_trace.h b/include/bt_trace.h
index 0b538a7..e89299a 100644
--- a/include/bt_trace.h
+++ b/include/bt_trace.h
@@ -79,6 +79,7 @@
 #define BTTRC_ID_STK_CE 51
 #define BTTRC_ID_STK_SNEP 52
 #define BTTRC_ID_STK_NDEF 53
+#define BTTRC_ID_STK_HIDD 54
 
 /* LayerIDs for BTA */
 #define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */
@@ -118,9 +119,9 @@
 
 /* LayerIDs for BT APP */
 #define BTTRC_ID_BTAPP 87
-#define BTTRC_ID_BT_PROTOCOL                          \
-  88 /* this is a temporary solution to allow dynamic \
-        enable/disable of BT_PROTOCOL_TRACE */
+/* this is a temporary solution to allow dynamic enable/disable of
+ * BT_PROTOCOL_TRACE */
+#define BTTRC_ID_BT_PROTOCOL 88
 #define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL
 #define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */
 
@@ -209,9 +210,7 @@
 #define BT_TRACE(l, t, ...) \
   LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__)
 
-/* Define tracing for the HCI unit
-*/
-
+/* Define tracing for the HCI unit */
 #define HCI_TRACE_ERROR(...)                                      \
   {                                                               \
     if (btu_trace_level >= BT_TRACE_LEVEL_ERROR)                  \
@@ -233,8 +232,7 @@
       BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* Define tracing for BTM
-*/
+/* Define tracing for BTM */
 #define BTM_TRACE_ERROR(...)                                      \
   {                                                               \
     if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
@@ -261,8 +259,7 @@
       BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the L2CAP unit
-*/
+/* Define tracing for the L2CAP unit */
 #define L2CAP_TRACE_ERROR(...)                                      \
   {                                                                 \
     if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR)             \
@@ -289,8 +286,7 @@
       BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the SDP unit
-*/
+/* Define tracing for the SDP unit */
 #define SDP_TRACE_ERROR(...)                                      \
   {                                                               \
     if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
@@ -317,8 +313,7 @@
       BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the RFCOMM unit
-*/
+/* Define tracing for the RFCOMM unit */
 #define RFCOMM_TRACE_ERROR(...)                                      \
   {                                                                  \
     if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR)                  \
@@ -394,8 +389,39 @@
       BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* define traces for BNEP */
+/* define traces for HID Device */
+#define HIDD_TRACE_ERROR(...)                                     \
+  {                                                               \
+    if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define HIDD_TRACE_WARNING(...)                                     \
+  {                                                                 \
+    if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define HIDD_TRACE_API(...)                                     \
+  {                                                             \
+    if (hd_cb.trace_level >= BT_TRACE_LEVEL_API)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define HIDD_TRACE_EVENT(...)                                     \
+  {                                                               \
+    if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define HIDD_TRACE_DEBUG(...)                                     \
+  {                                                               \
+    if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+#define HIDD_TRACE_VERBOSE(...)                                   \
+  {                                                               \
+    if (hd_cb.trace_level >= BT_TRACE_LEVEL_VERBOSE)              \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
 
+/* define traces for BNEP */
 #define BNEP_TRACE_ERROR(...)                                      \
   {                                                                \
     if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
@@ -423,7 +449,6 @@
   }
 
 /* define traces for PAN */
-
 #define PAN_TRACE_ERROR(...)                                      \
   {                                                               \
     if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
@@ -450,8 +475,7 @@
       BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the A2DP profile
-*/
+/* Define tracing for the A2DP profile */
 #define A2DP_TRACE_ERROR(...)                                      \
   {                                                                \
     if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
@@ -478,8 +502,7 @@
       BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_API, ##__VA_ARGS__); \
   }
 
-/* AVDTP
-*/
+/* AVDTP */
 #define AVDT_TRACE_ERROR(...)                                     \
   {                                                               \
     if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
@@ -506,8 +529,7 @@
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the AVCTP protocol
-*/
+/* Define tracing for the AVCTP protocol */
 #define AVCT_TRACE_ERROR(...)                                     \
   {                                                               \
     if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
@@ -534,8 +556,7 @@
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the AVRCP profile
-*/
+/* Define tracing for the AVRCP profile */
 #define AVRC_TRACE_ERROR(...)                                     \
   {                                                               \
     if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
@@ -562,8 +583,7 @@
       BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
   }
 
-/* MCAP
-*/
+/* MCAP */
 #define MCA_TRACE_ERROR(...)                                      \
   {                                                               \
     if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
@@ -590,8 +610,7 @@
       BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the ATT/GATT unit
-*/
+/* Define tracing for the ATT/GATT unit */
 #define GATT_TRACE_ERROR(...)                                     \
   {                                                               \
     if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
@@ -618,8 +637,7 @@
       BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
   }
 
-/* Define tracing for the SMP unit
-*/
+/* Define tracing for the SMP unit */
 #define SMP_TRACE_ERROR(...)                                      \
   {                                                               \
     if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
diff --git a/main/bte_logmsg.cc b/main/bte_logmsg.cc
index 74c544a..98ff1cf 100644
--- a/main/bte_logmsg.cc
+++ b/main/bte_logmsg.cc
@@ -53,6 +53,13 @@
 #if (PAN_INCLUDED == TRUE)
 #include "pan_api.h"
 #endif
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_api.h"
+#endif
+#if (HID_DEV_INCLUDED == TRUE)
+#include "hidd_api.h"
+#endif
+
 #include "gatt_api.h"
 #include "smp_api.h"
 
@@ -112,6 +119,10 @@
 #endif
     {BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, BTM_SetTraceLevel, "TRC_BTM",
      DEFAULT_CONF_TRACE_LEVEL},
+#if (HID_HOST_INCLUDED == TRUE)
+    {BTTRC_ID_STK_HID, BTTRC_ID_STK_HID, HID_HostSetTraceLevel, "TRC_HID_HOST",
+     DEFAULT_CONF_TRACE_LEVEL},
+#endif
     {BTTRC_ID_STK_GAP, BTTRC_ID_STK_GAP, GAP_SetTraceLevel, "TRC_GAP",
      DEFAULT_CONF_TRACE_LEVEL},
 #if (PAN_INCLUDED == TRUE)
@@ -124,6 +135,10 @@
      DEFAULT_CONF_TRACE_LEVEL},
     {BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP",
      DEFAULT_CONF_TRACE_LEVEL},
+#if (HID_DEV_INCLUDED == TRUE)
+    {BTTRC_ID_STK_HIDD, BTTRC_ID_STK_HIDD, HID_DevSetTraceLevel, "TRC_HID_DEV",
+     DEFAULT_CONF_TRACE_LEVEL},
+#endif
 
     /* LayerIDs for BTA, currently everything maps onto appl_trace_level.
      */
diff --git a/stack/Android.mk b/stack/Android.mk
index e03a96e..b412128 100644
--- a/stack/Android.mk
+++ b/stack/Android.mk
@@ -102,6 +102,8 @@
     ./hcic/hcicmds.cc \
     ./hid/hidh_api.cc \
     ./hid/hidh_conn.cc \
+    ./hid/hidd_api.cc \
+    ./hid/hidd_conn.cc \
     ./l2cap/l2c_api.cc \
     ./l2cap/l2c_ble.cc \
     ./l2cap/l2c_csm.cc \
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 41353ed..435b38f 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -85,6 +85,8 @@
     "hcic/hcicmds.cc",
     "hid/hidh_api.cc",
     "hid/hidh_conn.cc",
+    "hid/hidd_api.cc",
+    "hid/hidd_conn.cc",
     "l2cap/l2c_api.cc",
     "l2cap/l2c_ble.cc",
     "l2cap/l2c_csm.cc",
diff --git a/stack/avrc/avrc_utils.cc b/stack/avrc/avrc_utils.cc
index 3d86b67..6504ac4 100644
--- a/stack/avrc/avrc_utils.cc
+++ b/stack/avrc/avrc_utils.cc
@@ -114,7 +114,7 @@
 
   if (!result) {
     AVRC_TRACE_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!",
-                     __FUNCTION__, attrib, value);
+                     __func__, attrib, value);
   }
   return result;
 }
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index b6f42c9..0ea54b4 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -235,7 +235,7 @@
                                tGATT_DISCONN_REASON reason,
                                tBT_TRANSPORT transport) {
   GATT_TRACE_EVENT("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
-                   __FUNCTION__,
+                   __func__,
                    (bda[0] << 24) + (bda[1] << 16) + (bda[2] << 8) + bda[3],
                    (bda[4] << 8) + bda[5], connected, conn_id, reason);
 
diff --git a/stack/hid/hidd_api.cc b/stack/hid/hidd_api.cc
new file mode 100644
index 0000000..adaba58
--- /dev/null
+++ b/stack/hid/hidd_api.cc
@@ -0,0 +1,626 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 Device API entry points
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+#include "hiddefs.h"
+
+#if HID_DYNAMIC_MEMORY == FALSE
+tHID_DEV_CTB hd_cb;
+#endif
+
+/*******************************************************************************
+ *
+ * Function         HID_DevInit
+ *
+ * Description      Initializes control block
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void HID_DevInit(void) {
+  uint8_t log_level = hd_cb.trace_level;
+
+  HIDD_TRACE_API("%s", __func__);
+
+  memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
+  hd_cb.trace_level = log_level;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetTraceLevel
+ *
+ * Description      This function sets the trace level for HID Dev. If called
+*with
+ *                  a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns          the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t HID_DevSetTraceLevel(uint8_t new_level) {
+  if (new_level != 0xFF) hd_cb.trace_level = new_level;
+
+  return (hd_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevRegister
+ *
+ * Description      Registers HID device with lower layers
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) {
+  tHID_STATUS st;
+
+  HIDD_TRACE_API("%s", __func__);
+
+  if (hd_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
+
+  if (host_cback == NULL) return HID_ERR_INVALID_PARAM;
+
+  /* Register with L2CAP */
+  if ((st = hidd_conn_reg()) != HID_SUCCESS) {
+    return st;
+  }
+
+  hd_cb.callback = host_cback;
+  hd_cb.reg_flag = TRUE;
+
+  if (hd_cb.pending_data) {
+    osi_free(hd_cb.pending_data);
+    hd_cb.pending_data = NULL;
+  }
+
+  return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevDeregister
+ *
+ * Description      Deregisters HID device with lower layers
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevDeregister(void) {
+  HIDD_TRACE_API("%s", __func__);
+
+  if (!hd_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+  hidd_conn_dereg();
+
+  hd_cb.reg_flag = FALSE;
+
+  return (HID_SUCCESS);
+}
+
+tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl) {
+  HIDD_TRACE_API("%s", __func__);
+
+  if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl,
+                            HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) {
+    HIDD_TRACE_ERROR("Security Registration 1 failed");
+    return (HID_ERR_NO_RESOURCES);
+  }
+
+  if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl,
+                            HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) {
+    HIDD_TRACE_ERROR("Security Registration 2 failed");
+    return (HID_ERR_NO_RESOURCES);
+  }
+
+  if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL,
+                            BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+                            HIDD_NOSEC_CHN)) {
+    HIDD_TRACE_ERROR("Security Registration 3 failed");
+    return (HID_ERR_NO_RESOURCES);
+  }
+
+  if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL,
+                            BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+                            HIDD_NOSEC_CHN)) {
+    HIDD_TRACE_ERROR("Security Registration 4 failed");
+    return (HID_ERR_NO_RESOURCES);
+  }
+
+  if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE,
+                            HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) {
+    HIDD_TRACE_ERROR("Security Registration 5 failed");
+    return (HID_ERR_NO_RESOURCES);
+  }
+
+  if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE,
+                            HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) {
+    HIDD_TRACE_ERROR("Security Registration 6 failed");
+    return (HID_ERR_NO_RESOURCES);
+  }
+
+  return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevAddRecord
+ *
+ * Description      Creates SDP record for HID device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description,
+                             char* p_provider, uint16_t subclass,
+                             uint16_t desc_len, uint8_t* p_desc_data) {
+  bool result = TRUE;
+
+  HIDD_TRACE_API("%s", __func__);
+
+  // Service Class ID List
+  if (result) {
+    uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
+    result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
+  }
+
+  // Protocol Descriptor List
+  if (result) {
+    tSDP_PROTOCOL_ELEM proto_list[2];
+
+    proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_list[0].num_params = 1;
+    proto_list[0].params[0] = BT_PSM_HIDC;
+
+    proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
+    proto_list[1].num_params = 0;
+
+    result &= SDP_AddProtocolList(handle, 2, proto_list);
+  }
+
+  // Language Base Attribute ID List
+  if (result) {
+    result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH,
+                                            LANG_ID_CHAR_ENCODE_UTF8,
+                                            LANGUAGE_BASE_ID);
+  }
+
+  // Additional Protocol Descriptor List
+  if (result) {
+    tSDP_PROTO_LIST_ELEM add_proto_list;
+
+    add_proto_list.num_elems = 2;
+    add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    add_proto_list.list_elem[0].num_params = 1;
+    add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
+    add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
+    add_proto_list.list_elem[1].num_params = 0;
+
+    result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
+  }
+
+  // Service Name (O)
+  // Service Description (O)
+  // Provider Name (O)
+  if (result) {
+    const char* srv_name = p_name;
+    const char* srv_desc = p_description;
+    const char* provider_name = p_provider;
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                               strlen(srv_name) + 1, (uint8_t*)srv_name);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
+                               TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
+                               (uint8_t*)srv_desc);
+
+    result &=
+        SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+                         strlen(provider_name) + 1, (uint8_t*)provider_name);
+  }
+
+  // Bluetooth Profile Descriptor List
+  if (result) {
+    const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
+    const uint16_t version = 0x0100;
+
+    result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
+  }
+
+  // HID Parser Version
+  if (result) {
+    uint8_t* p;
+    const uint16_t rel_num = 0x0100;
+    const uint16_t parser_version = 0x0111;
+    const uint16_t prof_ver = 0x0100;
+    const uint8_t dev_subclass = subclass;
+    const uint8_t country_code = 0x21;
+    const uint8_t bool_false = 0x00;
+    const uint8_t bool_true = 0x01;
+    uint16_t temp;
+
+    p = (uint8_t*)&temp;
+    UINT16_TO_BE_STREAM(p, rel_num);
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM,
+                               UINT_DESC_TYPE, 2, (uint8_t*)&temp);
+
+    p = (uint8_t*)&temp;
+    UINT16_TO_BE_STREAM(p, parser_version);
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION,
+                               UINT_DESC_TYPE, 2, (uint8_t*)&temp);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS,
+                               UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE,
+                               1, (uint8_t*)&country_code);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE,
+                               BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE,
+                               BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+    {
+      static uint8_t cdt = 0x22;
+      uint8_t* p_buf;
+      uint8_t seq_len = 4 + desc_len;
+
+      p_buf = (uint8_t*)osi_malloc(2048);
+
+      if (p_buf == NULL) {
+        HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ",
+                         __func__);
+        return HID_ERR_NOT_REGISTERED;
+      }
+
+      p = p_buf;
+
+      UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+      UINT8_TO_BE_STREAM(p, seq_len);
+
+      UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+      UINT8_TO_BE_STREAM(p, cdt);
+
+      UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+      UINT8_TO_BE_STREAM(p, desc_len);
+      ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
+
+      result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST,
+                                 DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
+
+      osi_free(p_buf);
+    }
+
+    {
+      uint8_t lang_buf[8];
+      p = lang_buf;
+      uint8_t seq_len = 6;
+      uint16_t lang_english = 0x0409;
+      UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+      UINT8_TO_BE_STREAM(p, seq_len);
+      UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+      UINT16_TO_BE_STREAM(p, lang_english);
+      UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+      UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
+      result &=
+          SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE,
+                           DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
+    }
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER,
+                               BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE,
+                               BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE,
+                               BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE,
+                               BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+    p = (uint8_t*)&temp;
+    UINT16_TO_BE_STREAM(p, prof_ver);
+    result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION,
+                               UINT_DESC_TYPE, 2, (uint8_t*)&temp);
+  }
+
+  if (result) {
+    uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+    result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+                                  &browse_group);
+  }
+
+  if (!result) {
+    HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
+
+    return HID_ERR_NOT_REGISTERED;
+  }
+
+  return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSendReport
+ *
+ * Description      Sends report
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
+                              uint16_t len, uint8_t* p_data) {
+  HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel,
+                     type, id, len);
+
+  if (channel == HID_CHANNEL_CTRL) {
+    return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len,
+                               p_data);
+  }
+
+  if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
+    // on INTR we can only send INPUT
+    return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA,
+                               HID_PAR_REP_TYPE_INPUT, id, len, p_data);
+  }
+
+  return HID_ERR_INVALID_PARAM;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevVirtualCableUnplug
+ *
+ * Description      Sends Virtual Cable Unplug
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevVirtualCableUnplug(void) {
+  HIDD_TRACE_API("%s", __func__);
+
+  return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL,
+                             HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevPlugDevice
+ *
+ * Description      Establishes virtual cable to given host
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevPlugDevice(BD_ADDR addr) {
+  hd_cb.device.in_use = TRUE;
+  memcpy(hd_cb.device.addr, addr, sizeof(BD_ADDR));
+
+  return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevUnplugDevice
+ *
+ * Description      Unplugs virtual cable from given host
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr) {
+  if (!memcmp(hd_cb.device.addr, addr, sizeof(BD_ADDR))) {
+    hd_cb.device.in_use = FALSE;
+    hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
+    hd_cb.device.conn.ctrl_cid = 0;
+    hd_cb.device.conn.intr_cid = 0;
+  }
+
+  return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevConnect
+ *
+ * Description      Connects to device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevConnect(void) {
+  if (!hd_cb.reg_flag) {
+    return HID_ERR_NOT_REGISTERED;
+  }
+
+  if (!hd_cb.device.in_use) {
+    return HID_ERR_INVALID_PARAM;
+  }
+
+  if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
+    return HID_ERR_ALREADY_CONN;
+  }
+
+  return hidd_conn_initiate();
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevDisconnect
+ *
+ * Description      Disconnects from device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevDisconnect(void) {
+  if (!hd_cb.reg_flag) {
+    return HID_ERR_NOT_REGISTERED;
+  }
+
+  if (!hd_cb.device.in_use) {
+    return HID_ERR_INVALID_PARAM;
+  }
+
+  if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
+    return HID_ERR_NO_CONNECTION;
+  }
+
+  return hidd_conn_disconnect();
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetIncomingPolicy
+ *
+ * Description      Sets policy for incoming connections (allowed/disallowed)
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSetIncomingPolicy(bool allow) {
+  hd_cb.allow_incoming = allow;
+
+  return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevReportError
+ *
+ * Description      Reports error for Set Report via HANDSHAKE
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevReportError(uint8_t error) {
+  uint8_t handshake_param;
+
+  HIDD_TRACE_API("%s: error = %d", __func__, error);
+
+  switch (error) {
+    case HID_PAR_HANDSHAKE_RSP_SUCCESS:
+    case HID_PAR_HANDSHAKE_RSP_NOT_READY:
+    case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
+    case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
+    case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
+    case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
+    case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
+      handshake_param = error;
+      break;
+    default:
+      handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
+      break;
+  }
+
+  return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0,
+                             NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevGetDevice
+ *
+ * Description      Returns the BD Address of virtually cabled device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevGetDevice(BD_ADDR* addr) {
+  HIDD_TRACE_API("%s", __func__);
+
+  if (hd_cb.device.in_use) {
+    memcpy(addr, hd_cb.device.addr, sizeof(BD_ADDR));
+  } else {
+    return HID_ERR_NOT_REGISTERED;
+  }
+
+  return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetIncomingQos
+ *
+ * Description      Sets Incoming QoS values for Interrupt L2CAP Channel
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate,
+                                  uint32_t token_bucket_size,
+                                  uint32_t peak_bandwidth, uint32_t latency,
+                                  uint32_t delay_variation) {
+  HIDD_TRACE_API("%s", __func__);
+
+  hd_cb.use_in_qos = TRUE;
+
+  hd_cb.in_qos.service_type = service_type;
+  hd_cb.in_qos.token_rate = token_rate;
+  hd_cb.in_qos.token_bucket_size = token_bucket_size;
+  hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
+  hd_cb.in_qos.latency = latency;
+  hd_cb.in_qos.delay_variation = delay_variation;
+
+  return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetOutgoingQos
+ *
+ * Description      Sets Outgoing QoS values for Interrupt L2CAP Channel
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate,
+                                  uint32_t token_bucket_size,
+                                  uint32_t peak_bandwidth, uint32_t latency,
+                                  uint32_t delay_variation) {
+  HIDD_TRACE_API("%s", __func__);
+
+  hd_cb.l2cap_intr_cfg.qos_present = TRUE;
+
+  hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
+  hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
+  hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
+  hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
+  hd_cb.l2cap_intr_cfg.qos.latency = latency;
+  hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
+
+  return HID_SUCCESS;
+}
diff --git a/stack/hid/hidd_conn.cc b/stack/hid/hidd_conn.cc
new file mode 100644
index 0000000..19f81e7
--- /dev/null
+++ b/stack/hid/hidd_conn.cc
@@ -0,0 +1,980 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+#include "hiddefs.h"
+
+#include "bt_utils.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+
+#include "osi/include/osi.h"
+
+static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm,
+                                   uint8_t id);
+static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
+static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
+static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
+static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg);
+static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
+
+static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
+                                              hidd_l2cif_connect_cfm,
+                                              NULL,
+                                              hidd_l2cif_config_ind,
+                                              hidd_l2cif_config_cfm,
+                                              hidd_l2cif_disconnect_ind,
+                                              hidd_l2cif_disconnect_cfm,
+                                              NULL,
+                                              hidd_l2cif_data_ind,
+                                              hidd_l2cif_cong_ind,
+                                              NULL};
+
+/*******************************************************************************
+ *
+ * Function         hidd_check_config_done
+ *
+ * Description      Checks if connection is configured and callback can be fired
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_check_config_done() {
+  tHID_CONN* p_hcon;
+
+  p_hcon = &hd_cb.device.conn;
+
+  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;
+
+    hd_cb.device.state = HIDD_DEV_CONNECTED;
+
+    hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
+
+    // send outstanding data on intr
+    if (hd_cb.pending_data) {
+      L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
+      hd_cb.pending_data = NULL;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+static void hidd_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
+                                    UNUSED_ATTR tBT_TRANSPORT transport,
+                                    void* p_ref_data, uint8_t res) {
+  tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
+
+  if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
+    p_dev->conn.disc_reason = HID_SUCCESS;
+    p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+    L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
+                    L2CAP_CONN_OK, L2CAP_CONN_OK);
+    L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
+  } else if (res != BTM_SUCCESS) {
+    HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
+
+    p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
+    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);
+    return;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_sec_check_complete_orig
+ *
+ * Description      HID security check complete callback function (device
+*originated)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void hidd_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr,
+                                  UNUSED_ATTR tBT_TRANSPORT transport,
+                                  void* p_ref_data, uint8_t res) {
+  tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
+
+  if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
+    HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__,
+                       p_dev->conn.conn_state);
+    return;
+  }
+
+  if (res == BTM_SUCCESS) {
+    HIDD_TRACE_EVENT("%s: security ok", __func__);
+    p_dev->conn.disc_reason = HID_SUCCESS;
+
+    p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
+    L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
+  } else {
+    HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
+    p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
+    hidd_conn_disconnect();
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_connect_ind
+ *
+ * Description      Handles incoming L2CAP connection (we act as server)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm,
+                                   uint8_t id) {
+  tHID_CONN* p_hcon;
+  tHID_DEV_DEV_CTB* p_dev;
+  bool accept = TRUE;  // accept by default
+
+  HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
+
+  p_dev = &hd_cb.device;
+
+  if (!hd_cb.allow_incoming) {
+    HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting",
+                       __func__);
+    L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
+    return;
+  }
+
+  if (p_dev->in_use && memcmp(bd_addr, p_dev->addr, sizeof(BD_ADDR))) {
+    HIDD_TRACE_WARNING(
+        "%s: incoming connections from different device, rejecting", __func__);
+    L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
+    return;
+  } else if (!p_dev->in_use) {
+    p_dev->in_use = TRUE;
+    memcpy(p_dev->addr, bd_addr, sizeof(BD_ADDR));
+    p_dev->state = HIDD_DEV_NO_CONN;
+  }
+
+  p_hcon = &hd_cb.device.conn;
+
+  switch (psm) {
+    case HID_PSM_INTERRUPT:
+      if (p_hcon->ctrl_cid == 0) {
+        accept = FALSE;
+        HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting",
+                           __func__);
+      }
+
+      if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
+        accept = FALSE;
+        HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting",
+                           __func__, p_hcon->conn_state);
+      }
+
+      break;
+
+    case HID_PSM_CONTROL:
+      if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
+        accept = FALSE;
+        HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting",
+                           __func__, p_hcon->conn_state);
+      }
+
+      break;
+
+    default:
+      accept = FALSE;
+      HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
+      break;
+  }
+
+  if (!accept) {
+    L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
+    return;
+  }
+
+  // for CTRL we need to go through security and we reply in callback from there
+  if (psm == HID_PSM_CONTROL) {
+    p_hcon->conn_flags = 0;
+    p_hcon->ctrl_cid = cid;
+    p_hcon->ctrl_id = id;
+    p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
+
+    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, HIDD_NOSEC_CHN,
+                                  &hidd_sec_check_complete,
+                                  p_dev) == BTM_CMD_STARTED) {
+      L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+    }
+
+    return;
+  }
+
+  // for INTR we go directly to config state
+  p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+  p_hcon->intr_cid = cid;
+
+  L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+  L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_connect_cfm
+ *
+ * Description      Handles L2CAP connection response (we act as client)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) {
+  tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
+  tHID_CONN* p_hcon = &hd_cb.device.conn;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
+
+  if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    return;
+  }
+
+  if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
+      ((cid == p_hcon->ctrl_cid) &&
+       (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
+      ((cid == p_hcon->intr_cid) &&
+       (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) {
+    HIDD_TRACE_WARNING("%s: unexpected", __func__);
+    return;
+  }
+
+  if (result != L2CAP_CONN_OK) {
+    HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
+
+    if (cid == p_hcon->ctrl_cid)
+      p_hcon->ctrl_cid = 0;
+    else
+      p_hcon->intr_cid = 0;
+
+    hidd_conn_disconnect();
+
+    hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+                   HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
+    return;
+  }
+
+  /* CTRL connect conf */
+  if (cid == p_hcon->ctrl_cid) {
+    p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+    p_hcon->disc_reason =
+        HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
+
+    btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE,
+                              BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
+                              &hidd_sec_check_complete_orig, p_dev);
+  } else {
+    p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+    L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
+  }
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_config_ind
+ *
+ * Description      Handles incoming L2CAP configuration request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+  tHID_CONN* p_hcon;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    return;
+  }
+
+  if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
+    p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
+  else
+    p_hcon->rem_mtu_size = p_cfg->mtu;
+
+  // accept without changes
+  p_cfg->flush_to_present = FALSE;
+  p_cfg->mtu_present = FALSE;
+  p_cfg->result = L2CAP_CFG_OK;
+
+  if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
+    p_cfg->qos_present = TRUE;
+    memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
+  }
+
+  L2CA_ConfigRsp(cid, p_cfg);
+
+  // update flags
+  if (cid == p_hcon->ctrl_cid) {
+    p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+
+    if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+        (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
+      p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
+      if ((p_hcon->intr_cid =
+               L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
+        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+        hidd_conn_disconnect();
+
+        HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
+                           __func__);
+        hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+                       HID_ERR_L2CAP_FAILED, NULL);
+        return;
+      } else {
+        p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+      }
+    }
+  } else {
+    p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+  }
+
+  hidd_check_config_done();
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_config_cfm
+ *
+ * Description      Handles incoming L2CAP configuration response
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+  tHID_CONN* p_hcon;
+  uint32_t reason;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid,
+                   p_cfg->result);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    return;
+  }
+
+  if (p_hcon->intr_cid == cid &&
+      p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
+    tL2CAP_CFG_INFO new_qos;
+
+    // QoS parameters not accepted for intr, try again with host proposal
+
+    memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
+    memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
+    new_qos.qos_present = TRUE;
+
+    HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
+
+    L2CA_ConfigReq(cid, &new_qos);
+    return;
+  } else if (p_hcon->intr_cid == cid &&
+             p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
+    // QoS not understood by remote device, try configuring without QoS
+
+    HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
+
+    L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
+    return;
+  } else if (p_cfg->result != L2CAP_CFG_OK) {
+    HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
+
+    hidd_conn_disconnect();
+    reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
+
+    hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
+    return;
+  }
+
+  // update flags
+  if (cid == p_hcon->ctrl_cid) {
+    p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+
+    if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+        (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
+      p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
+      if ((p_hcon->intr_cid =
+               L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
+        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+        hidd_conn_disconnect();
+
+        HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
+                           __func__);
+        hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+                       HID_ERR_L2CAP_FAILED, NULL);
+        return;
+      } else {
+        p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+      }
+    }
+  } else {
+    p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+  }
+
+  hidd_check_config_done();
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_disconnect_ind
+ *
+ * Description      Handler incoming L2CAP disconnection request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) {
+  tHID_CONN* p_hcon;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+      (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    return;
+  }
+
+  if (ack_needed) L2CA_DisconnectRsp(cid);
+
+  p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+  if (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)) {
+    HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
+
+    // clean any outstanding data on intr
+    if (hd_cb.pending_data) {
+      osi_free(hd_cb.pending_data);
+      hd_cb.pending_data = NULL;
+    }
+
+    hd_cb.device.state = HIDD_DEV_NO_CONN;
+    p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+    hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason,
+                   NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_disconnect_cfm
+ *
+ * Description      Handles L2CAP disconection response
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) {
+  tHID_CONN* p_hcon;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+      (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    return;
+  }
+
+  if (cid == p_hcon->ctrl_cid) {
+    p_hcon->ctrl_cid = 0;
+  } else {
+    p_hcon->intr_cid = 0;
+
+    // now disconnect CTRL
+    L2CA_DisconnectReq(p_hcon->ctrl_cid);
+  }
+
+  if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
+    HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
+
+    hd_cb.device.state = HIDD_DEV_NO_CONN;
+    p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+    if (hd_cb.pending_vc_unplug) {
+      hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG,
+                     p_hcon->disc_reason, NULL);
+      hd_cb.pending_vc_unplug = FALSE;
+    } else {
+      hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+                     p_hcon->disc_reason, NULL);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_cong_ind
+ *
+ * Description      Handles L2CAP congestion status event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) {
+  tHID_CONN* p_hcon;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+      (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    return;
+  }
+
+  if (congested) {
+    p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+  } else {
+    p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_l2cif_data_ind
+ *
+ * Description      Handler incoming data on L2CAP channel
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) {
+  tHID_CONN* p_hcon;
+  uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
+  uint8_t msg_type, param;
+  bool err = FALSE;
+
+  HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+      (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+    HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+    osi_free(p_msg);
+    return;
+  }
+
+  msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
+  param = HID_GET_PARAM_FROM_HDR(*p_data);
+
+  if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
+    // skip HID header
+    p_msg->offset++;
+    p_msg->len--;
+
+    hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
+    return;
+  }
+
+  switch (msg_type) {
+    case HID_TRANS_GET_REPORT:
+      // at this stage we don't know if Report Id shall be included in request
+      // so we pass complete packet in callback and let other code analyze this
+      hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT,
+                     !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
+      break;
+
+    case HID_TRANS_SET_REPORT:
+      // as above
+      hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
+      break;
+
+    case HID_TRANS_GET_IDLE:
+      hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
+                          HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0,
+                          NULL);
+      osi_free(p_msg);
+      break;
+
+    case HID_TRANS_SET_IDLE:
+      if (p_msg->len != 2) {
+        HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received",
+                         __func__, p_msg->len);
+        err = TRUE;
+      } else {
+        hd_cb.device.idle_time = p_data[1];
+        HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__,
+                         hd_cb.device.idle_time);
+        if (hd_cb.device.idle_time) {
+          HIDD_TRACE_WARNING(
+              "%s: idle_time of %d ms not supported by HID Device", __func__,
+              (hd_cb.device.idle_time * 4));
+          err = TRUE;
+        }
+      }
+      if (!err) {
+        hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
+                            HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
+      } else {
+        hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
+                            HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0,
+                            NULL);
+      }
+      osi_free(p_msg);
+      break;
+
+    case HID_TRANS_GET_PROTOCOL:
+      hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
+                          HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0,
+                          NULL);
+      osi_free(p_msg);
+      break;
+
+    case HID_TRANS_SET_PROTOCOL:
+      hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
+      hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL,
+                     param & HID_PAR_PROTOCOL_MASK, NULL);
+      hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS,
+                          0, 0, NULL);
+      osi_free(p_msg);
+      break;
+
+    case HID_TRANS_CONTROL:
+      switch (param) {
+        case HID_PAR_CONTROL_SUSPEND:
+          hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
+          break;
+
+        case HID_PAR_CONTROL_EXIT_SUSPEND:
+          hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0,
+                         NULL);
+          break;
+
+        case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+          hidd_conn_disconnect();
+
+          // set flag so we can notify properly when disconnected
+          hd_cb.pending_vc_unplug = TRUE;
+          break;
+      }
+
+      osi_free(p_msg);
+      break;
+
+    case HID_TRANS_DATA:
+    default:
+      HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
+      hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
+                          HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0,
+                          NULL);
+      osi_free(p_msg);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_conn_reg
+ *
+ * Description      Registers L2CAP channels
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_reg(void) {
+  HIDD_TRACE_API("%s", __func__);
+
+  memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+  hd_cb.l2cap_cfg.mtu_present = TRUE;
+  hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
+  hd_cb.l2cap_cfg.flush_to_present = TRUE;
+  hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
+
+  memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+  hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
+  hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
+  hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
+  hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
+
+  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+    HIDD_TRACE_ERROR("HID Control (device) registration failed");
+    return (HID_ERR_L2CAP_FAILED);
+  }
+
+  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+    L2CA_Deregister(HID_PSM_CONTROL);
+    HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
+    return (HID_ERR_L2CAP_FAILED);
+  }
+
+  return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_conn_dereg
+ *
+ * Description      Deregisters L2CAP channels
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void hidd_conn_dereg(void) {
+  HIDD_TRACE_API("%s", __func__);
+
+  L2CA_Deregister(HID_PSM_CONTROL);
+  L2CA_Deregister(HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_conn_initiate
+ *
+ * Description      Initiates HID connection to plugged device
+ *
+ * Returns          HID_SUCCESS
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_initiate(void) {
+  tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
+
+  HIDD_TRACE_API("%s", __func__);
+
+  if (!p_dev->in_use) {
+    HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
+    return (HID_ERR_NOT_REGISTERED);
+  }
+
+  if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
+    HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
+    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;
+
+  p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
+
+  BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
+
+  /* Check if L2CAP started the connection process */
+  if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) ==
+      0) {
+    HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
+    hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED,
+                   NULL);
+  } else {
+    p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+  }
+
+  return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_conn_disconnect
+ *
+ * Description      Disconnects existing HID connection
+ *
+ * Returns          HID_SUCCESS
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_disconnect(void) {
+  tHID_CONN* p_hcon;
+
+  HIDD_TRACE_API("%s", __func__);
+
+  // clean any outstanding data on intr
+  if (hd_cb.pending_data) {
+    osi_free(hd_cb.pending_data);
+    hd_cb.pending_data = NULL;
+  }
+
+  p_hcon = &hd_cb.device.conn;
+
+  if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
+    p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+    /* Set l2cap idle timeout to 0 (so ACL link is disconnected
+     * immediately after last channel is closed) */
+    L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
+
+    if (p_hcon->intr_cid) {
+      L2CA_DisconnectReq(p_hcon->intr_cid);
+    } else if (p_hcon->ctrl_cid) {
+      L2CA_DisconnectReq(p_hcon->ctrl_cid);
+    }
+  } else {
+    HIDD_TRACE_WARNING("%s: already disconnected", __func__);
+    p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+  }
+
+  return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         hidd_conn_send_data
+ *
+ * Description      Sends data to host
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
+                                uint8_t param, uint8_t data, uint16_t len,
+                                uint8_t* p_data) {
+  tHID_CONN* p_hcon;
+  BT_HDR* p_buf;
+  uint8_t* p_out;
+  uint16_t cid;
+  uint16_t buf_size;
+
+  HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__,
+                     channel, msg_type, len);
+
+  p_hcon = &hd_cb.device.conn;
+
+  if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
+    return HID_ERR_CONGESTED;
+  }
+
+  switch (msg_type) {
+    case HID_TRANS_HANDSHAKE:
+    case HID_TRANS_CONTROL:
+      cid = p_hcon->ctrl_cid;
+      buf_size = HID_CONTROL_BUF_SIZE;
+      break;
+    case HID_TRANS_DATA:
+      if (channel == HID_CHANNEL_CTRL) {
+        cid = p_hcon->ctrl_cid;
+        buf_size = HID_CONTROL_BUF_SIZE;
+      } else {
+        cid = p_hcon->intr_cid;
+        buf_size = HID_INTERRUPT_BUF_SIZE;
+      }
+      break;
+    default:
+      return (HID_ERR_INVALID_PARAM);
+  }
+
+  p_buf = (BT_HDR*)osi_malloc(buf_size);
+  if (p_buf == NULL) return (HID_ERR_NO_RESOURCES);
+
+  p_buf->offset = L2CAP_MIN_OFFSET;
+
+  p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+  *p_out = HID_BUILD_HDR(msg_type, param);
+  p_out++;
+
+  p_buf->len = 1;  // start with header only
+
+  // add report id prefix only if non-zero (which is reserved)
+  if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
+    *p_out = data;  // report_id
+    p_out++;
+    p_buf->len++;
+  }
+
+  if (len > 0 && p_data != NULL) {
+    memcpy(p_out, p_data, len);
+    p_buf->len += len;
+  }
+
+  // check if connected
+  if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
+    // for DATA on intr we hold transfer and try to reconnect
+    if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
+      // drop previous data, we do not queue it for now
+      if (hd_cb.pending_data) {
+        osi_free(hd_cb.pending_data);
+      }
+
+      hd_cb.pending_data = p_buf;
+
+      if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
+        hidd_conn_initiate();
+      }
+
+      return HID_SUCCESS;
+    }
+
+    return HID_ERR_NO_CONNECTION;
+  }
+
+#ifdef REPORT_TRANSFER_TIMESTAMP
+  if (report_transfer) {
+    HIDD_TRACE_ERROR("%s: report sent", __func__);
+  }
+#endif
+  HIDD_TRACE_VERBOSE("%s: report sent", __func__);
+
+  if (!L2CA_DataWrite(cid, p_buf)) return (HID_ERR_CONGESTED);
+
+  return (HID_SUCCESS);
+}
diff --git a/stack/hid/hidd_int.h b/stack/hid/hidd_int.h
new file mode 100644
index 0000000..cce1302
--- /dev/null
+++ b/stack/hid/hidd_int.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 DEVICE internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDD_INT_H
+#define HIDD_INT_H
+
+#include "hid_conn.h"
+#include "hidd_api.h"
+#include "l2c_api.h"
+
+enum { HIDD_DEV_NO_CONN, HIDD_DEV_CONNECTED };
+
+typedef struct device_ctb {
+  bool in_use;
+  BD_ADDR addr;
+
+  uint8_t state;
+
+  tHID_CONN conn;
+
+  bool boot_mode;
+
+  uint8_t idle_time;
+} tHID_DEV_DEV_CTB;
+
+typedef struct dev_ctb {
+  tHID_DEV_DEV_CTB device;
+
+  tHID_DEV_HOST_CALLBACK* callback;
+  tL2CAP_CFG_INFO l2cap_cfg;
+  tL2CAP_CFG_INFO l2cap_intr_cfg;
+
+  bool use_in_qos;
+  FLOW_SPEC in_qos;
+
+  bool reg_flag;
+  uint8_t trace_level;
+
+  bool allow_incoming;
+
+  BT_HDR* pending_data;
+
+  bool pending_vc_unplug;
+} tHID_DEV_CTB;
+
+extern tHID_STATUS hidd_conn_reg(void);
+extern void hidd_conn_dereg(void);
+extern tHID_STATUS hidd_conn_initiate(void);
+extern tHID_STATUS hidd_conn_disconnect(void);
+extern tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
+                                       uint8_t param, uint8_t data,
+                                       uint16_t len, uint8_t* p_data);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+#if HID_DYNAMIC_MEMORY == FALSE
+extern tHID_DEV_CTB hd_cb;
+#else
+extern tHID_DEV_CTB* hidd_cb_ptr;
+#define hd_cb (*hidd_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/stack/hid/hidh_api.cc b/stack/hid/hidh_api.cc
index c3ab315..a290b77 100644
--- a/stack/hid/hidh_api.cc
+++ b/stack/hid/hidh_api.cc
@@ -230,18 +230,14 @@
  *
  ******************************************************************************/
 void HID_HostInit(void) {
+  uint8_t log_level = hh_cb.trace_level;
   memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
+  hh_cb.trace_level = log_level;
 
   for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
     hh_cb.devices[i].conn.process_repage_timer =
         alarm_new("hid_devices_conn.process_repage_timer");
   }
-
-#if defined(HID_INITIAL_TRACE_LEVEL)
-  hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
-#else
-  hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
-#endif
 }
 
 /*******************************************************************************
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index 935fc6d..39dc61c 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -1223,9 +1223,12 @@
 #define BTM_SEC_SERVICE_HDP_SNK 48
 #define BTM_SEC_SERVICE_HDP_SRC 49
 #define BTM_SEC_SERVICE_ATT 50
+#define BTM_SEC_SERVICE_HIDD_SEC_CTRL 51
+#define BTM_SEC_SERVICE_HIDD_NOSEC_CTRL 52
+#define BTM_SEC_SERVICE_HIDD_INTR 53
 
 /* Update these as services are added */
-#define BTM_SEC_SERVICE_FIRST_EMPTY 51
+#define BTM_SEC_SERVICE_FIRST_EMPTY 54
 
 #ifndef BTM_SEC_MAX_SERVICES
 #define BTM_SEC_MAX_SERVICES 75
diff --git a/stack/include/hidd_api.h b/stack/include/hidd_api.h
new file mode 100644
index 0000000..0db58dc
--- /dev/null
+++ b/stack/include/hidd_api.h
@@ -0,0 +1,260 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  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 HIDD_API_H
+#define HIDD_API_H
+
+#include "hiddefs.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ *  Type Definitions
+ ****************************************************************************/
+
+enum { HID_CHANNEL_INTR, HID_CHANNEL_CTRL };
+
+/*
+    HID_DHOST_EVT_OPEN  - connected to host device (CTRL and INTR), data = n/a
+    HID_DHOST_EVT_CLOSE - disconnected from host device, data=reason
+    HID_DHOST_EVT_GET_REPORT - got GET_REPORT from host
+    HID_DHOST_EVT_SET_REPORT - got SET_REPORT from host
+    HID_DHOST_EVT_SET_PROTOCOL - got SET_PROTOCOL from host
+*/
+
+enum {
+  HID_DHOST_EVT_OPEN,
+  HID_DHOST_EVT_CLOSE,
+  HID_DHOST_EVT_GET_REPORT,
+  HID_DHOST_EVT_SET_REPORT,
+  HID_DHOST_EVT_SET_PROTOCOL,
+  HID_DHOST_EVT_INTR_DATA,
+  HID_DHOST_EVT_VC_UNPLUG,
+  HID_DHOST_EVT_SUSPEND,
+  HID_DHOST_EVT_EXIT_SUSPEND,
+};
+typedef void(tHID_DEV_HOST_CALLBACK)(BD_ADDR bd_addr, uint8_t event,
+                                     uint32_t data, BT_HDR* p_buf);
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         HID_DevInit
+ *
+ * Description      Initializes control block
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void HID_DevInit(void);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevRegister
+ *
+ * Description      Registers HID device with lower layers
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevDeregister
+ *
+ * Description      Deregisters HID device with lower layers
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevDeregister(void);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetSecurityLevel
+ *
+ * Description      Sets security level for HID device connections
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevAddRecord
+ *
+ * Description      Creates SDP record for HID device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name,
+                                    char* p_description, char* p_provider,
+                                    uint16_t subclass, uint16_t desc_len,
+                                    uint8_t* p_desc_data);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSendReport
+ *
+ * Description      Sends report
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
+                                     uint16_t len, uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevVirtualCableUnplug
+ *
+ * Description      Sends Virtual Cable Unplug
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevVirtualCableUnplug(void);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevPlugDevice
+ *
+ * Description      Establishes virtual cable to given host
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevPlugDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevUnplugDevice
+ *
+ * Description      Unplugs virtual cable from given host
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevConnect
+ *
+ * Description      Connects to device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevConnect(void);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevDisconnect
+ *
+ * Description      Disconnects from device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevDisconnect(void);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetIncomingPolicy
+ *
+ * Description      Sets policy for incoming connections (allowed/disallowed)
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetIncomingPolicy(bool allow);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevReportError
+ *
+ * Description      Reports error for Set Report via HANDSHAKE
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevReportError(uint8_t error);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevGetDevice
+ *
+ * Description      Returns the BD Address of virtually cabled device
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevGetDevice(BD_ADDR* addr);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetIncomingQos
+ *
+ * Description      Sets Incoming QoS values for Interrupt L2CAP Channel
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetIncomingQos(
+    uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
+    uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetOutgoingQos
+ *
+ * Description      Sets Outgoing QoS values for Interrupt L2CAP Channel
+ *
+ * Returns          tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetOutgoingQos(
+    uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
+    uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);
+
+/*******************************************************************************
+ *
+ * Function         HID_DevSetTraceLevel
+ *
+ * Description      This function sets the trace level for HID Dev. If called
+ *                  with a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns          the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t HID_DevSetTraceLevel(uint8_t new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HIDD_API_H */