LE: Add support for the HID-over-GATT profile (1/3)

bug:8330048
Change-Id: I5727161b0a87700487bee96cdffa8fd169034204
diff --git a/bta/Android.mk b/bta/Android.mk
index 7d1c19e..2a2551f 100644
--- a/bta/Android.mk
+++ b/bta/Android.mk
@@ -42,6 +42,7 @@
     ./hh/bta_hh_cfg.c \
     ./hh/bta_hh_act.c \
     ./hh/bta_hh_api.c \
+    ./hh/bta_hh_le.c \
     ./hh/bta_hh_utils.c \
     ./hh/bta_hh_main.c \
     ./pb/bta_pbs_cfg.c \
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
index 38a382e..06a2279 100644
--- a/bta/dm/bta_dm_act.c
+++ b/bta/dm/bta_dm_act.c
@@ -180,7 +180,7 @@
     BTM_SEC_SERVICE_SAP,                    /* BTA_SAP_SERVICE_ID */
     BTM_SEC_SERVICE_AVDTP,                  /* BTA_A2DP_SERVICE_ID */
     BTM_SEC_SERVICE_AVCTP,                  /* BTA_AVRCP_SERVICE_ID */
-    BTM_SEC_SERVICE_HID_SEC_CTRL,           /* BTA_HID_SERVICE_ID */
+    BTM_SEC_SERVICE_HIDH_SEC_CTRL,          /* BTA_HID_SERVICE_ID */
     BTM_SEC_SERVICE_AVDTP,                  /* BTA_VDP_SERVICE_ID */
     BTM_SEC_SERVICE_PBAP,                   /* BTA_PBAP_SERVICE_ID */
     BTM_SEC_SERVICE_HEADSET,                /* BTA_HSP_HS_SERVICE_ID */
diff --git a/bta/hh/bta_hh_act.c b/bta/hh/bta_hh_act.c
index f2b91e0..1c83d07 100644
--- a/bta/hh/bta_hh_act.c
+++ b/bta/hh/bta_hh_act.c
@@ -42,8 +42,8 @@
 /*****************************************************************************
 **  Local Function prototypes
 *****************************************************************************/
-static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data,
-                          BT_HDR *pdata);
+static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event,
+                            UINT32 data, BT_HDR *pdata);
 static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result);
 
 #if BTA_HH_DEBUG
@@ -96,6 +96,13 @@
             bta_hh_cb.cb_index[xx]          = BTA_HH_IDX_INVALID;
     }
 
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    if (status == BTA_HH_OK)
+    {
+        bta_hh_le_enable();
+    }
+    else
+#endif
         /* signal BTA call back event */
         (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status);
 }
@@ -160,6 +167,11 @@
     if (HID_HostDeregister()!= HID_SUCCESS)
         status = BTA_HH_ERR;
 
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    bta_hh_le_deregister();
+    return;
+#endif
+
     bta_hh_cleanup_disable(status);
 }
 
@@ -187,9 +199,9 @@
             attr_mask |= HID_SEC_REQUIRED;
 
 #if BTA_HH_DEBUG
-        APPL_TRACE_EVENT3("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \
-                            attr_mask 0x%02x", \
-                            p_cb, result, attr_mask);
+        APPL_TRACE_EVENT4("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \
+                            attr_mask 0x%02x, handle %x", \
+                            p_cb, result, attr_mask,p_cb->hid_handle);
 #endif
 
         /* check to see type of device is supported , and should not been added before */
@@ -235,7 +247,6 @@
     /* free disc_db when SDP is completed */
     utl_freebuf((void **)&bta_hh_cb.p_disc_db);
 
-
     /* send SDP_CMPL_EVT into state machine */
     bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
 
@@ -259,6 +270,7 @@
 #if BTA_HH_DEBUG
     APPL_TRACE_EVENT2("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result);
 #endif
+
     /* if DI record does not exist on remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be
          * set to 0xffff and we will allow the connection to go through. Spec mandates that DI
          * record be set, but many HID devices do not set this. So for IOP purposes, we allow the
@@ -328,6 +340,14 @@
     p_cb->mode      = p_data->api_conn.mode;
     bta_hh_cb.p_cur = p_cb;
 
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr))
+    {
+        bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr);
+        return;
+    }
+#endif
+
     /* if previously virtually cabled device, skip SDP */
     if (p_cb->app_id)
     {
@@ -337,7 +357,7 @@
 #endif
         if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
         {
-            if ((HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl)) \
+            if (HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl) \
                 == HID_SUCCESS)
             {
                 /* update device CB with newly register device handle */
@@ -451,8 +471,18 @@
 
     if (status != BTA_HH_OK)
     {
+        /* Check if this was incoming connection request  from an unknown device
+           **and connection failed due to missing HID Device SDP UUID
+           **In above condition, disconnect the link as well as remove the
+           **device from list of HID devices*/
+        if ((status == BTA_HH_ERR_SDP) &&
+           (p_cb->incoming_conn) &&(p_cb->app_id == 0))
+        {
+            APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl:SDP failed for  incoming conn :hndl %d",
+                                p_cb->incoming_hid_handle);
+            HID_HostRemoveDev( p_cb->incoming_hid_handle);
+        }
         conn_dat.status = status;
-
         (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
 
         /* move state machine W4_CONN ->IDLE */
@@ -464,12 +494,10 @@
             /* clean up device control block */
             bta_hh_clean_up_kdev(p_cb);
         }
-
 #if BTA_HH_DEBUG
         bta_hh_trace_dev_db();
 #endif
     }
-
     return;
 }
 
@@ -488,16 +516,24 @@
     tBTA_HH_CBDATA    disc_dat;
     tHID_STATUS     status;
 
-    /* found an active connection */
-    disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle;
-    disc_dat.status = BTA_HH_ERR;
+#if BTA_HH_LE_INCLUDED == TRUE
+    if (p_cb->is_le_device)
+        bta_hh_le_api_disc_act(p_cb);
+    else
+#endif
+    {
+        /* found an active connection */
+        disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle;
+        disc_dat.status = BTA_HH_ERR;
 
-    status = HID_HostCloseDev(disc_dat.handle);
+        status = HID_HostCloseDev(disc_dat.handle);
 
-    if (status)
-        (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat);
+        if (status)
+            (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat);
+    }
 
     return;
+
 }
 /*******************************************************************************
 **
@@ -526,8 +562,23 @@
     bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class,
                        p_cb->attr_mask,  p_cb->app_id);
 
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    conn.status = p_cb->status;
+    conn.le_hid = p_cb->is_le_device;
+    conn.scps_supported = p_cb->scps_supported;
+
+    if (!p_cb->is_le_device)
+#endif
+    {
+        /* inform role manager */
+        bta_sys_conn_open( BTA_ID_HH ,p_cb->app_id, p_cb->addr);
+    }
     /* set protocol mode when not default report mode */
-    if (p_cb->mode != BTA_HH_PROTO_RPT_MODE)
+    if ( p_cb->mode != BTA_HH_PROTO_RPT_MODE
+#if (BTA_HH_LE_INCLUDED == TRUE)
+         && !p_cb->is_le_device
+#endif
+        )
     {
         if ((HID_HostWriteDev(dev_handle,
                               HID_TRANS_SET_PROTOCOL, HID_PAR_PROTOCOL_BOOT_MODE,
@@ -548,6 +599,7 @@
         (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn);
 
     p_cb->incoming_conn = FALSE;
+    p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
 
 }
 /*******************************************************************************
@@ -564,10 +616,10 @@
 {
     tBTA_HH_API_CONN    conn_data;
 
-#if BTA_HH_DEBUG
     UINT8   dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \
                         p_cb->hid_handle;
 
+#if BTA_HH_DEBUG
     APPL_TRACE_EVENT1 ("bta_hh_open_act:  Device[%d] connected", dev_handle);
 #endif
 
@@ -581,6 +633,8 @@
         performed, do it first */
     {
         p_cb->incoming_conn = TRUE;
+        /* store the handle here in case sdp fails - need to disconnect */
+        p_cb->incoming_hid_handle = dev_handle;
 
         memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN));
         bdcpy(conn_data.bd_addr, p_cb->addr);
@@ -635,6 +689,7 @@
 #endif
 
     memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA));
+    memset(&cback_data, 0, sizeof(tBTA_HH_CBDATA));
 
     switch (p_cb->w4_evt)
     {
@@ -753,6 +808,47 @@
 
 /*******************************************************************************
 **
+** Function         bta_hh_open_failure
+**
+** Description      report HID open failure when at wait for connection state and receive
+**                  device close event.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+    tBTA_HH_CONN            conn_dat ;
+    UINT32                  reason = p_data->hid_cback.data;    /* Reason for closing (32-bit) */
+
+    memset(&conn_dat, 0, sizeof(tBTA_HH_CONN));
+     conn_dat.handle = p_cb->hid_handle;
+     conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
+                                    BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+     bdcpy(conn_dat.bda, p_cb->addr);
+     HID_HostCloseDev(p_cb->hid_handle);
+
+     /* Report OPEN fail event */
+     (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+#if BTA_HH_DEBUG
+    bta_hh_trace_dev_db();
+#endif
+    /* clean up control block, but retain SDP info and device handle */
+    p_cb->vp            = FALSE;
+    p_cb->w4_evt        = 0;
+
+    /* if no connection is active and HH disable is signaled, disable service */
+    if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable)
+    {
+        bta_hh_disc_cmpl();
+    }
+
+}
+
+/*******************************************************************************
+**
 ** Function         bta_hh_close_act
 **
 ** Description      HID Host process a close event
@@ -844,6 +940,13 @@
 *******************************************************************************/
 void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
 {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    if (p_cb->is_le_device)
+    {
+        bta_hh_le_get_dscp_act(p_cb);
+    }
+    else
+#endif
     (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info);
 }
 
@@ -873,19 +976,36 @@
         /* initialize callback data */
         if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE)
         {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+            if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr))
+            {
+                dev_info.handle   = bta_hh_le_add_device(p_cb, p_dev_info);
+                dev_info.status   = BTA_HH_OK;
+            }
+            else
+#endif
+
             if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\
                             == HID_SUCCESS)
             {
                 dev_info.handle   = dev_handle;
                 dev_info.status   = BTA_HH_OK;
 
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
                 /* update DI information */
                 bta_hh_update_di_info(p_cb,
                                       p_dev_info->dscp_info.vendor_id,
                                       p_dev_info->dscp_info.product_id,
                                       p_dev_info->dscp_info.version,
+                                      p_dev_info->dscp_info.flag);
+#else
+                bta_hh_update_di_info(p_cb,
+                                      p_dev_info->dscp_info.vendor_id,
+                                      p_dev_info->dscp_info.product_id,
+                                      p_dev_info->dscp_info.version,
                                       0);
 
+#endif
                 /* add to BTA device list */
                 bta_hh_add_device_to_list(p_cb, dev_handle,
                                           p_dev_info->attr_mask,
@@ -912,6 +1032,15 @@
         dev_info.handle = (UINT8)p_dev_info->hdr.layer_specific;
         bdcpy(dev_info.bda, p_cb->addr);
 
+#if BTA_HH_LE_INCLUDED == TRUE
+        if (p_cb->is_le_device)
+        {
+            bta_hh_le_remove_dev_bg_conn(p_cb);
+            bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+            bta_hh_clean_up_kdev(p_cb);
+        }
+        else
+#endif
         {
             if(HID_HostRemoveDev( dev_info.handle ) == HID_SUCCESS)
             {
@@ -945,6 +1074,13 @@
     UINT16  event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                         BTA_HH_FST_TRANS_CB_EVT;
 
+#if BTA_HH_LE_INCLUDED == TRUE
+    if (p_cb->is_le_device)
+        bta_hh_le_write_dev_act(p_cb, p_data);
+    else
+#endif
+    {
+
     cbdata.handle = p_cb->hid_handle;
 
     /* match up BTE/BTA report/boot mode def */
@@ -1022,7 +1158,7 @@
         }
     }
 
-
+    }
     return;
 }
 
@@ -1039,8 +1175,8 @@
 ** Returns          void
 **
 *******************************************************************************/
-static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data,
-                          BT_HDR *pdata)
+static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event,
+                        UINT32 data, BT_HDR *pdata)
 {
     tBTA_HH_CBACK_DATA    *p_buf = NULL;
     UINT16  sm_event = BTA_HH_INVALID_EVT;
@@ -1093,6 +1229,7 @@
         p_buf->hdr.event  = sm_event;
         p_buf->hdr.layer_specific = (UINT16)dev_handle;
         p_buf->data       = data;
+        bdcpy(p_buf->addr, addr);
         p_buf->p_data     = pdata;
 
         bta_sys_sendmsg(p_buf);
diff --git a/bta/hh/bta_hh_api.c b/bta/hh/bta_hh_api.c
index 2a7965e..1e71d91 100644
--- a/bta/hh/bta_hh_api.c
+++ b/bta/hh/bta_hh_api.c
@@ -305,6 +305,13 @@
 *******************************************************************************/
 void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR  *p_data)
 {
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+        if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT)
+        {
+            APPL_TRACE_ERROR0("ERROR! Wrong report type! Write Command only valid for output report!");
+            return;
+        }
+#endif
     bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, 0, 0, p_data);
 }
 
@@ -406,7 +413,37 @@
         bta_sys_sendmsg(p_buf);
     }
 }
+#if BTA_HH_LE_INCLUDED == TRUE
 
+/*******************************************************************************
+**
+** Function         BTA_HhUpdateLeScanParam
+**
+** Description      Update the scan paramteters if connected to a LE hid device as
+**                  report host.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTA_HhUpdateLeScanParam(UINT8 dev_handle, UINT16 scan_int, UINT16 scan_win)
+{
+    tBTA_HH_SCPP_UPDATE    *p_buf;
+
+    p_buf = (tBTA_HH_SCPP_UPDATE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_SCPP_UPDATE));
+
+    if (p_buf != NULL)
+    {
+        memset(p_buf, 0, sizeof(tBTA_HH_SCPP_UPDATE));
+
+        p_buf->hdr.event            = BTA_HH_API_SCPP_UPDATE_EVT;
+        p_buf->hdr.layer_specific   = (UINT16) dev_handle;
+        p_buf->scan_int             =  scan_int;
+        p_buf->scan_win             =  scan_win;
+
+        bta_sys_sendmsg(p_buf);
+    }
+}
+#endif
 /*******************************************************************************/
 /*                          Utility Function                                   */
 /*******************************************************************************/
diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h
index 7630a3a..0fa7c17 100644
--- a/bta/hh/bta_hh_int.h
+++ b/bta/hh/bta_hh_int.h
@@ -30,9 +30,17 @@
 #include "utl.h"
 #include "bta_hh_api.h"
 
+#if BTA_HH_LE_INCLUDED == TRUE
+#include "bta_gatt_api.h"
+#endif
+
 /* can be moved to bta_api.h */
 #define BTA_HH_MAX_RPT_CHARS    8
 
+#if (BTA_GATT_INCLUDED == FALSE || BLE_INCLUDED == FALSE)
+#undef BTA_HH_LE_INCLUDED
+#define BTA_HH_LE_INCLUDED      FALSE
+#endif
 
 /* state machine events, these events are handled by the state machine */
 enum
@@ -49,6 +57,17 @@
     BTA_HH_API_GET_DSCP_EVT,
     BTA_HH_API_MAINT_DEV_EVT,
     BTA_HH_OPEN_CMPL_EVT,
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    BTA_HH_GATT_CLOSE_EVT,
+    BTA_HH_GATT_OPEN_EVT,
+    BTA_HH_START_ENC_EVT,
+    BTA_HH_ENC_CMPL_EVT,
+    BTA_HH_GATT_READ_CHAR_CMPL_EVT,
+    BTA_HH_GATT_WRITE_CHAR_CMPL_EVT,
+    BTA_HH_GATT_READ_DESCR_CMPL_EVT,
+    BTA_HH_GATT_WRITE_DESCR_CMPL_EVT,
+    BTA_HH_API_SCPP_UPDATE_EVT,
+#endif
 
     /* not handled by execute state machine */
     BTA_HH_API_ENABLE_EVT,
@@ -74,6 +93,11 @@
     BTA_HH_IDLE_ST,
     BTA_HH_W4_CONN_ST,
     BTA_HH_CONN_ST
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    ,BTA_HH_W4_SEC
+#endif
+    ,BTA_HH_INVALID_ST    /* Used to check invalid states before executing SM function */
+
 };
 typedef UINT8 tBTA_HH_STATE;
 
@@ -84,6 +108,9 @@
     UINT8            t_type;
     UINT8            param;
     UINT8            rpt_id;
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    UINT8            srvc_id;
+#endif
     UINT16           data;
     BT_HDR           *p_data;
 }tBTA_HH_CMD_DATA;
@@ -109,6 +136,7 @@
 typedef struct
 {
     BT_HDR          hdr;
+    BD_ADDR         addr;
     UINT32          data;
     BT_HDR          *p_data;
 }tBTA_HH_CBACK_DATA;
@@ -124,6 +152,22 @@
     tBTA_HH_DEV_DSCP_INFO      dscp_info;
 }tBTA_HH_MAINT_DEV;
 
+#if BTA_HH_LE_INCLUDED == TRUE
+typedef struct
+{
+    BT_HDR              hdr;
+    UINT16              conn_id;
+    tBTA_GATT_REASON    reason;         /* disconnect reason code, not useful when connect event is reported */
+
+}tBTA_HH_LE_CLOSE;
+
+typedef struct
+{
+    BT_HDR              hdr;
+    UINT16              scan_int;
+    UINT16              scan_win;
+}tBTA_HH_SCPP_UPDATE;
+#endif
 /* union of all event data types */
 typedef union
 {
@@ -134,8 +178,67 @@
     tBTA_HH_CBACK_DATA       hid_cback;
     tBTA_HH_STATUS           status;
     tBTA_HH_MAINT_DEV        api_maintdev;
+#if BTA_HH_LE_INCLUDED == TRUE
+    tBTA_HH_LE_CLOSE         le_close;
+    tBTA_GATTC_OPEN          le_open;
+    tBTA_HH_SCPP_UPDATE      le_scpp_update;
+#endif
 } tBTA_HH_DATA;
 
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+typedef struct
+{
+    UINT8                   index;
+    BOOLEAN                 in_use;
+    UINT8                   inst_id;    /* share service instance ID and report instance ID, as
+                                           hi 4 for service instance ID, low 4 as charatceristic instance ID */
+    tBTA_HH_RPT_TYPE	    rpt_type;
+    UINT16                  uuid;
+    UINT16				    prop;
+    UINT8				    rpt_id;
+    BOOLEAN			        client_cfg_exist;
+    UINT16				    client_cfg_value;
+}tBTA_HH_LE_RPT;
+
+#ifndef BTA_HH_LE_RPT_MAX
+#define BTA_HH_LE_RPT_MAX       10
+#endif
+
+typedef struct
+{
+    BOOLEAN                 in_use;
+    tBTA_HH_LE_RPT		    report[BTA_HH_LE_RPT_MAX];
+
+#define BTA_HH_LE_PROTO_MODE_BIT        0x01
+#define BTA_HH_LE_CP_BIT                0x02
+    UINT8		            option_char; /* control point char exisit or not */
+
+    BOOLEAN                 expl_incl_srvc;
+    UINT8                   incl_srvc_inst; /* assuming only one included service : battery service */
+    UINT8                   cur_expl_char_idx; /* currently discovering service index */
+
+#define BTA_HH_LE_REMOTE_WAKE   0x01
+#define BTA_HH_LE_NORMAL_CONN   0x02
+    UINT8                   flag;           /* HID Information flag */
+    UINT8                   *rpt_map;
+    UINT16                  ext_rpt_ref;
+    tBTA_HH_DEV_DESCR       descriptor;
+
+}tBTA_HH_LE_HID_SRVC;
+
+#ifndef BTA_HH_LE_HID_SRVC_MAX
+#define BTA_HH_LE_HID_SRVC_MAX      1
+#endif
+
+/* convert a HID handle to the LE CB index */
+#define BTA_HH_GET_LE_CB_IDX(x)         (((x) >> 4) - 1)
+/* convert a GATT connection ID to HID device handle, it is the hi 4 bits of a UINT8 */
+#define BTA_HH_GET_LE_DEV_HDL(x)        (UINT8)(((x)  + 1) << 4)
+/* check to see if th edevice handle is a LE device handle */
+#define BTA_HH_IS_LE_DEV_HDL(x)        ((x) & 0xf0)
+#define BTA_HH_IS_LE_DEV_HDL_VALID(x)  (((x)>>4) < BTA_HH_LE_MAX_KNOWN)
+#endif
+
 /* device control block */
 typedef struct
 {
@@ -147,13 +250,39 @@
     UINT8               sub_class;      /* Cod sub class */
     UINT8               sec_mask;       /* security mask */
     UINT8               app_id;         /* application ID for this connection */
-    UINT8               hid_handle;     /* device handle */
+    UINT8               hid_handle;     /* device handle : low 4 bits for regular HID: HID_HOST_MAX_DEVICES can not exceed 15;
+                                                            high 4 bits for LE HID: GATT_MAX_PHY_CHANNEL can not exceed 15 */
     BOOLEAN             vp;             /* virtually unplug flag */
     BOOLEAN             in_use;         /* control block currently in use */
     BOOLEAN             incoming_conn;  /* is incoming connection? */
+    UINT8               incoming_hid_handle;  /* temporary handle for incoming connection? */
     BOOLEAN             opened;         /* TRUE if device successfully opened HID connection */
     tBTA_HH_PROTO_MODE  mode;           /* protocol mode */
     tBTA_HH_STATE       state;          /* CB state */
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_DISC_NONE     0x00
+#define BTA_HH_LE_DISC_HIDS     0x01
+#define BTA_HH_LE_DISC_DIS      0x02
+#define BTA_HH_LE_DISC_SCPS     0x04
+
+    UINT8               disc_active;
+    tBTA_HH_STATUS      status;
+    BOOLEAN             is_le_device;
+    tBTA_HH_LE_HID_SRVC hid_srvc[BTA_HH_LE_HID_SRVC_MAX];
+    UINT16              conn_id;
+    BOOLEAN             in_bg_conn;
+    UINT8               total_srvc;
+    UINT8               clt_cfg_idx;
+    UINT8               cur_srvc_index; /* currently discovering service index */
+    BOOLEAN             scps_supported;
+
+#define BTA_HH_LE_SCPS_NOTIFY_NONE    0
+#define BTA_HH_LE_SCPS_NOTIFY_SPT  0x01
+#define BTA_HH_LE_SCPS_NOTIFY_ENB  0x02
+    UINT8               scps_notify;   /* scan refresh supported/notification enabled */
+#endif
+
 } tBTA_HH_DEV_CB;
 
 /* key board parsing control block */
@@ -179,6 +308,10 @@
                                                        block idx, used in sdp */
     UINT8                   cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index
                                                         map to dev handle */
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    UINT8                   le_cb_index[BTA_HH_MAX_DEVICE]; /* maintain a CB index map to LE dev handle */
+    tBTA_GATTC_IF           gatt_if;
+#endif
     tBTA_HH_CBACK       *p_cback;               /* Application callbacks */
     tSDP_DISCOVERY_DB*      p_disc_db;
     UINT8                   trace_level;            /* tracing level */
@@ -217,6 +350,7 @@
 extern void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
 extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
 extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
 
 /* utility functions */
 extern UINT8  bta_hh_find_cb(BD_ADDR bda);
@@ -244,6 +378,33 @@
 
 extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout);
 
+/* functions for LE HID */
+extern void bta_hh_le_enable(void);
+extern void bta_hh_le_deregister(void);
+extern BOOLEAN bta_hh_is_le_device(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_open_conn(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB *p_cb);
+extern void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB *p_cb);
+extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info);
+extern void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB *p_cb);
+extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_gatt_open(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_gatt_close(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_start_srvc_discovery(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_w4_le_read_char_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_read_char_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_w4_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_w4_le_write_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_write_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_write_char_descr_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+extern void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
+
+
 #if BTA_HH_DEBUG
 extern void bta_hh_trace_dev_db(void);
 #endif
diff --git a/bta/hh/bta_hh_le.c b/bta/hh/bta_hh_le.c
new file mode 100644
index 0000000..41512d4
--- /dev/null
+++ b/bta/hh/bta_hh_le.c
@@ -0,0 +1,2909 @@
+/*****************************************************************************
+**
+**  Name:           bta_hh_le.c
+**
+**  Description:    This file contains the HID host over LE
+**                  functions.
+**
+**  Copyright (c) 2005-2011, Broadcom Corp, All Rights Reserved.
+**  Broadcom Bluetooth Core. Proprietary and confidential.
+**
+*****************************************************************************/
+
+#include "bta_api.h"
+#include "bta_hh_int.h"
+
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+
+#include "bta_api.h"
+#include <string.h>
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "bta_hh_co.h"
+#include "bta_gatt_api.h"
+#include "srvc_api.h"
+
+#ifndef BTA_HH_LE_RECONN
+#define BTA_HH_LE_RECONN    TRUE
+#endif
+
+#define BTA_HH_APP_ID_LE            0xff
+
+#define BTA_HH_LE_RPT_TYPE_VALID(x)     ((x) <= BTA_LE_HID_RPT_FEATURE && (x)>=BTA_LE_HID_RPT_INPUT)
+
+#define BTA_HH_LE_RPT_INST_ID_MAP(s,c)  (UINT8)(((s)<<4)||(c))
+#define BTA_HH_LE_RPT_GET_SRVC_INST_ID(x)  (UINT8)(x  >> 4)
+#define BTA_HH_LE_RPT_GET_RPT_INST_ID(x)  (UINT8)(x & 0x0f)
+
+
+#define BTA_HH_LE_PROTO_BOOT_MODE      0x00
+#define BTA_HH_LE_PROTO_REPORT_MODE      0x01
+
+#define BTA_HH_SCPP_INST_DEF            0
+
+#define BTA_HH_LE_DISC_CHAR_NUM     8
+static const UINT16 bta_hh_le_disc_char_uuid[BTA_HH_LE_DISC_CHAR_NUM] =
+{
+    GATT_UUID_HID_INFORMATION,
+    GATT_UUID_HID_REPORT_MAP,
+    GATT_UUID_HID_CONTROL_POINT,
+    GATT_UUID_HID_REPORT,
+    GATT_UUID_HID_BT_KB_INPUT,
+    GATT_UUID_HID_BT_KB_OUTPUT,
+    GATT_UUID_HID_BT_MOUSE_INPUT,
+    GATT_UUID_HID_PROTO_MODE        /* always make sure this is the last attribute to discover */
+};
+
+#define BTA_LE_HID_RTP_UUID_MAX     5
+static const UINT16 bta_hh_uuid_to_rtp_type[BTA_LE_HID_RTP_UUID_MAX][2] =
+{
+    {GATT_UUID_HID_REPORT,       BTA_HH_RPTT_INPUT},
+    {GATT_UUID_HID_BT_KB_INPUT,  BTA_HH_RPTT_INPUT},
+    {GATT_UUID_HID_BT_KB_OUTPUT, BTA_HH_RPTT_OUTPUT},
+    {GATT_UUID_HID_BT_MOUSE_INPUT, BTA_HH_RPTT_INPUT},
+    {GATT_UUID_BATTERY_LEVEL,      BTA_HH_RPTT_INPUT}
+};
+
+
+static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data);
+static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB *p_dev_cb);
+static void bta_hh_le_search_hid_included(tBTA_HH_DEV_CB *p_dev_cb);
+static void bta_hh_le_search_scps(tBTA_HH_DEV_CB *p_cb);
+static void bta_hh_le_search_scps_chars(tBTA_HH_DEV_CB *p_cb);
+static void bta_hh_le_register_scpp_notif(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status);
+static void bta_hh_le_register_scpp_notif_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status);
+static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond);
+
+#define BTA_HH_LE_SRVC_DEF      0
+
+#if BTA_HH_DEBUG == TRUE
+static const char *bta_hh_le_rpt_name[4] =
+{
+    "UNKNOWN",
+    "INPUT",
+    "OUTPUT",
+    "FEATURE"
+};
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_hid_report_dbg
+**
+** Description      debug function to print out all HID report available on remote
+**                  device.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB *p_cb)
+{
+    UINT8 i , j;
+    tBTA_HH_LE_RPT  *p_rpt;
+    char *  rpt_name;
+
+    APPL_TRACE_DEBUG0("HID Report DB");
+    for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++)
+    {
+        if (p_cb->hid_srvc[i].in_use)
+        {
+            p_rpt = &p_cb->hid_srvc[i].report[0];
+
+            APPL_TRACE_DEBUG1("\t HID serivce inst: %d", i);
+
+            for (j = 0; j < BTA_HH_LE_RPT_MAX; j ++, p_rpt++)
+            {
+                rpt_name = "Unknown";
+                if (p_rpt->in_use)
+                {
+                    if (p_rpt->uuid == GATT_UUID_HID_REPORT)
+                        rpt_name = "Report";
+                    if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT)
+                        rpt_name = "Boot KB Input";
+                    if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT)
+                        rpt_name = "Boot KB Output";
+                    if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
+                        rpt_name = "Boot MI Input";
+
+
+                    APPL_TRACE_DEBUG6("\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [inst_id: %d]  [Clt_cfg: %d]",
+                        rpt_name,
+                        p_rpt->uuid ,
+                        ((p_rpt->rpt_type < 4) ? bta_hh_le_rpt_name[p_rpt->rpt_type] : "UNKNOWN"),
+                        p_rpt->rpt_id,
+                        p_rpt->inst_id,
+                        p_rpt->client_cfg_value);
+                }
+                else
+                    break;
+            }
+        }
+        else
+            break;
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_uuid_to_str
+**
+** Description
+**
+** Returns          void
+**
+*******************************************************************************/
+static char *bta_hh_uuid_to_str(UINT16 uuid)
+{
+    switch(uuid)
+    {
+        case GATT_UUID_HID_INFORMATION:
+            return "GATT_UUID_HID_INFORMATION";
+        case GATT_UUID_HID_REPORT_MAP:
+            return "GATT_UUID_HID_REPORT_MAP";
+        case GATT_UUID_HID_CONTROL_POINT:
+            return "GATT_UUID_HID_CONTROL_POINT";
+        case GATT_UUID_HID_REPORT:
+            return "GATT_UUID_HID_REPORT";
+        case GATT_UUID_HID_PROTO_MODE:
+            return "GATT_UUID_HID_PROTO_MODE";
+        case GATT_UUID_HID_BT_KB_INPUT:
+            return "GATT_UUID_HID_BT_KB_INPUT";
+        case GATT_UUID_HID_BT_KB_OUTPUT:
+            return "GATT_UUID_HID_BT_KB_OUTPUT";
+        case GATT_UUID_HID_BT_MOUSE_INPUT:
+            return "GATT_UUID_HID_BT_MOUSE_INPUT";
+        case GATT_UUID_CHAR_CLIENT_CONFIG:
+            return "GATT_UUID_CHAR_CLIENT_CONFIG";
+        case GATT_UUID_EXT_RPT_REF_DESCR:
+            return "GATT_UUID_EXT_RPT_REF_DESCR";
+        case GATT_UUID_RPT_REF_DESCR:
+            return "GATT_UUID_RPT_REF_DESCR";
+        default:
+            return "Unknown UUID";
+    }
+}
+#endif
+/*******************************************************************************
+**
+** Function         bta_hh_le_enable
+**
+** Description      initialize LE HID related functionality
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_enable(void)
+{
+    char       app_name[LEN_UUID_128 + 1];
+    tBT_UUID    app_uuid = {LEN_UUID_128,{0}};
+    UINT8       xx;
+
+    bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+
+    for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++)
+        bta_hh_cb.le_cb_index[xx]       = BTA_HH_IDX_INVALID;
+
+    memset (app_name, 0, LEN_UUID_128 + 1);
+    strncpy(app_name, "BTA HH OVER LE", LEN_UUID_128);
+
+    memcpy((void *)app_uuid.uu.uuid128, (void *)app_name, LEN_UUID_128);
+
+    BTA_GATTC_AppRegister(&app_uuid, bta_hh_gattc_callback);
+
+    return;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_register_cmpl
+**
+** Description      BTA HH register with BTA GATTC completed
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_register_cmpl(tBTA_GATTC_REG *p_reg)
+{
+    tBTA_HH_STATUS      status = BTA_HH_ERR;
+
+    if (p_reg->status == BTA_GATT_OK)
+    {
+        bta_hh_cb.gatt_if = p_reg->client_if;
+        status = BTA_HH_OK;
+    }
+    else
+        bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+
+    /* signal BTA call back event */
+    (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_deregister
+**
+** Description      De-register BTA HH from BTA GATTC
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_deregister(void)
+{
+    BTA_GATTC_AppDeregister(bta_hh_cb.gatt_if);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_is_le_device
+**
+** Description      Check to see if the remote device is a LE only device
+**
+** Parameters:
+**
+*******************************************************************************/
+BOOLEAN bta_hh_is_le_device(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda)
+{
+    p_cb->is_le_device = BTM_UseLeLink (remote_bda);
+
+    return p_cb->is_le_device;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_hid_srvc_cached
+**
+** Description      Check to see if LE HID service has been discovered and cached
+**
+** Parameters:      TRUE : has cache; FALSE: none.
+**
+*******************************************************************************/
+BOOLEAN bta_hh_le_hid_srvc_cached(tBTA_HH_DEV_CB *p_dev_cb)
+{
+    if (p_dev_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].in_use)
+        return TRUE;
+    else
+        return FALSE;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_add_hid_srvc_entry
+**
+** Description      Add a HID service entry in the HID device control block
+**
+** Parameters:
+**
+*******************************************************************************/
+BOOLEAN bta_hh_le_add_hid_srvc_entry(tBTA_HH_DEV_CB *p_dev_cb, UINT8 idx)
+{
+    BOOLEAN added = FALSE;
+
+    if (idx < BTA_HH_LE_HID_SRVC_MAX)
+    {
+        p_dev_cb->hid_srvc[idx].in_use = TRUE;
+        added = TRUE;
+    }
+    else
+    {
+        APPL_TRACE_ERROR0("DB full,max HID service entry!");
+    }
+    return added;
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_open_conn
+**
+** Description      open a GATT connection first.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_open_conn(tBTA_HH_DEV_CB *p_cb, BD_ADDR remote_bda)
+{
+    /* update cb_index[] map */
+    p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+    memcpy(p_cb->addr, remote_bda, BD_ADDR_LEN);
+    bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+    p_cb->in_use = TRUE;
+
+    BTA_GATTC_Open(bta_hh_cb.gatt_if, remote_bda, TRUE);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_fill_16bits_gatt_id
+**
+** Description      Utility function to fill a GATT ID strucure
+**
+*******************************************************************************/
+void bta_hh_le_fill_16bits_gatt_id(UINT8 inst_id, UINT16 uuid,  tBTA_GATT_ID *p_output)
+{
+    p_output->inst_id        = inst_id;
+    p_output->uuid.len       = LEN_UUID_16;
+    p_output->uuid.uu.uuid16 = uuid;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_fill_16bits_srvc_id
+**
+** Description      Utility function to fill a service ID strucure with a 16 bits
+**                  service UUID.
+**
+*******************************************************************************/
+void bta_hh_le_fill_16bits_srvc_id(BOOLEAN is_pri, UINT8 inst_id, UINT16 srvc_uuid,
+                                   tBTA_GATT_SRVC_ID *p_output)
+{
+    memset((void *)p_output, 0, sizeof(tBTA_GATT_SRVC_ID));
+    p_output->is_primary        = is_pri;
+    bta_hh_le_fill_16bits_gatt_id(inst_id, srvc_uuid, &p_output->id);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_fill_16bits_char_id
+**
+** Description      Utility function to fill a char ID strucure with a 16 bits
+**                  char UUID.
+**
+*******************************************************************************/
+void bta_hh_le_fill_16bits_char_id(UINT8 inst_id, UINT16 char_uuid,
+                                   tBTA_GATT_ID *p_output)
+{
+    memset((void *)p_output, 0, sizeof(tBTA_GATT_ID));
+    bta_hh_le_fill_16bits_gatt_id(inst_id, char_uuid, p_output);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_find_dev_cb_by_conn_id
+**
+** Description      Utility function find a device control block by connection ID.
+**
+*******************************************************************************/
+tBTA_HH_DEV_CB * bta_hh_le_find_dev_cb_by_conn_id(UINT16 conn_id)
+{
+    UINT8   i;
+    tBTA_HH_DEV_CB *p_dev_cb = &bta_hh_cb.kdev[0];
+
+    for (i = 0; i < BTA_HH_MAX_DEVICE; i ++, p_dev_cb ++)
+    {
+        if (p_dev_cb->in_use  && p_dev_cb->conn_id == conn_id)
+            return p_dev_cb;
+    }
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_find_dev_cb_by_bda
+**
+** Description      Utility function find a device control block by BD address.
+**
+*******************************************************************************/
+tBTA_HH_DEV_CB * bta_hh_le_find_dev_cb_by_bda(BD_ADDR bda)
+{
+    UINT8   i;
+    tBTA_HH_DEV_CB *p_dev_cb = &bta_hh_cb.kdev[0];
+
+    for (i = 0; i < BTA_HH_MAX_DEVICE; i ++, p_dev_cb ++)
+    {
+        if (p_dev_cb->in_use  &&
+            memcmp(p_dev_cb->addr, bda, BD_ADDR_LEN) == 0)
+            return p_dev_cb;
+    }
+    return NULL;
+}
+UINT8 bta_hh_le_find_service_inst_by_battery_inst_id(tBTA_HH_DEV_CB *p_cb, UINT8 ba_inst_id)
+{
+    UINT8   i;
+
+    for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++)
+    {
+        if (p_cb->hid_srvc[i].in_use &&
+            p_cb->hid_srvc[i].incl_srvc_inst == ba_inst_id)
+        {
+            return i;
+        }
+    }
+    return BTA_HH_IDX_INVALID;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_find_report_entry
+**
+** Description      find the report entry by service instance and report UUID and
+**                  instance ID
+**
+*******************************************************************************/
+tBTA_HH_LE_RPT * bta_hh_le_find_report_entry(tBTA_HH_DEV_CB *p_cb,
+                                             UINT8  srvc_inst_id,  /* service instance ID */
+                                             UINT16 rpt_uuid,
+                                             UINT8  char_inst_id)
+{
+    UINT8   i;
+    UINT8   hid_inst_id = srvc_inst_id;
+    tBTA_HH_LE_RPT *p_rpt;
+
+    if (rpt_uuid == GATT_UUID_BATTERY_LEVEL)
+    {
+        hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id);
+
+        if (hid_inst_id == BTA_HH_IDX_INVALID)
+            return NULL;
+    }
+
+    p_rpt = &p_cb->hid_srvc[hid_inst_id].report[0];
+
+    for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++)
+    {
+        if (p_rpt->uuid == rpt_uuid &&
+            p_rpt->inst_id == BTA_HH_LE_RPT_INST_ID_MAP(srvc_inst_id, char_inst_id))
+        {
+
+            return p_rpt;
+        }
+    }
+    return NULL;
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_find_rpt_by_idtype
+**
+** Description      find a report entry by report ID and protocol mode
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTA_HH_LE_RPT * bta_hh_le_find_rpt_by_idtype(tBTA_HH_LE_RPT*p_head, UINT8 mode,
+                                              tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id)
+{
+    tBTA_HH_LE_RPT *p_rpt = p_head;
+    UINT8   i;
+
+#if BTA_HH_DEBUG == TRUE
+    APPL_TRACE_DEBUG2("bta_hh_le_find_rpt_by_idtype: r_tpye: %d rpt_id: %d", r_type, rpt_id);
+#endif
+
+    for (i = 0 ; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt++)
+    {
+        if (p_rpt->in_use && p_rpt->rpt_id == rpt_id && r_type == p_rpt->rpt_type)
+        {
+            /* return battery report w/o condition */
+            if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL)
+                return p_rpt;
+
+            if (mode == BTA_HH_PROTO_RPT_MODE && p_rpt->uuid == GATT_UUID_HID_REPORT)
+                return p_rpt;
+
+            if ( mode ==BTA_HH_PROTO_BOOT_MODE &&
+                (p_rpt->uuid >= GATT_UUID_HID_BT_KB_INPUT && p_rpt->uuid <= GATT_UUID_HID_BT_MOUSE_INPUT))
+                return p_rpt;
+        }
+    }
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_find_alloc_report_entry
+**
+** Description      find or allocate a report entry in the HID service report list.
+**
+*******************************************************************************/
+tBTA_HH_LE_RPT * bta_hh_le_find_alloc_report_entry(tBTA_HH_DEV_CB *p_cb,
+                                                   UINT8 srvc_inst_id,
+                                                   UINT16 rpt_uuid,
+                                                   UINT8  inst_id,
+                                                   UINT8  prop)
+{
+    UINT8   i, hid_inst_id = srvc_inst_id;
+    tBTA_HH_LE_RPT *p_rpt;
+
+    if (rpt_uuid == GATT_UUID_BATTERY_LEVEL)
+    {
+        hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id);
+
+        if (hid_inst_id == BTA_HH_IDX_INVALID)
+            return NULL;
+    }
+    p_rpt = &p_cb->hid_srvc[hid_inst_id].report[0];
+
+    for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++)
+    {
+        if (!p_rpt->in_use ||
+            (p_rpt->uuid == rpt_uuid &&
+             p_rpt->inst_id == BTA_HH_LE_RPT_INST_ID_MAP(srvc_inst_id, inst_id)))
+        {
+            if (!p_rpt->in_use)
+            {
+                p_rpt->in_use   = TRUE;
+                p_rpt->index    = i;
+                p_rpt->inst_id  = BTA_HH_LE_RPT_INST_ID_MAP(srvc_inst_id, inst_id);
+                p_rpt->prop     = prop;
+                p_rpt->uuid     = rpt_uuid;
+
+                /* assign report type */
+                for (i = 0; i < BTA_LE_HID_RTP_UUID_MAX; i ++)
+                {
+                    if (bta_hh_uuid_to_rtp_type[i][0] == rpt_uuid)
+                    {
+                        p_rpt->rpt_type = (tBTA_HH_RPT_TYPE)bta_hh_uuid_to_rtp_type[i][1];
+
+                        if (rpt_uuid == GATT_UUID_HID_BT_KB_INPUT || rpt_uuid == GATT_UUID_HID_BT_KB_OUTPUT)
+                            p_rpt->rpt_id = BTA_HH_KEYBD_RPT_ID;
+
+                        if (rpt_uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
+                            p_rpt->rpt_id = BTA_HH_MOUSE_RPT_ID;
+
+                        break;
+                    }
+                }
+            }
+
+            return p_rpt;
+        }
+    }
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_read_char_dscrpt
+**
+** Description      read cahracteristic descriptor
+**
+*******************************************************************************/
+tBTA_HH_STATUS bta_hh_le_read_char_dscrpt(tBTA_HH_DEV_CB *p_cb, UINT16 srvc_uuid, UINT8 srvc_inst_id,
+                                UINT16 char_uuid, UINT8 char_inst_id, UINT16 char_descp_uuid)
+{
+    tBTA_GATTC_CHAR_ID  char_id;
+    tBT_UUID        descr_uuid;
+    tBTA_GATTC_CHAR_DESCR_ID    descr_id;
+    tBTA_HH_STATUS  status = BTA_HH_ERR;
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst_id, srvc_uuid, &char_id.srvc_id);
+    bta_hh_le_fill_16bits_char_id(char_inst_id, char_uuid, &char_id.char_id);
+
+    descr_uuid.len       = LEN_UUID_16;
+    descr_uuid.uu.uuid16 = char_descp_uuid;
+
+    /* find the report reference descriptor */
+    if (BTA_GATTC_GetFirstCharDescr(p_cb->conn_id,
+                                &char_id,
+                                &descr_uuid,
+                                &descr_id) == BTA_GATT_OK)
+    {
+        BTA_GATTC_ReadCharDescr(p_cb->conn_id,
+                                &descr_id,
+                                BTA_GATT_AUTH_REQ_NONE);
+
+        status = BTA_HH_OK;
+    }
+    else
+    {
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_ERROR2("bta_hh_le_read_char_dscrpt: No such descrpt exists: %s(0x%04x)",
+            bta_hh_uuid_to_str(char_descp_uuid), char_descp_uuid);
+#endif
+    }
+    return status;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_read_rpt_ref_descr
+**
+** Description      read report refernece descriptors in service discovery process
+**
+*******************************************************************************/
+void bta_hh_le_read_rpt_ref_descr(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_LE_RPT *p_rpt)
+{
+    BOOLEAN started = FALSE;
+    UINT16  srvc_uuid, char_uuid;
+
+    while (p_rpt != NULL)
+    {
+        if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT)
+        {
+            /* is battery report */
+            if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL)
+            {
+#if BTA_HH_DEBUG == TRUE
+                APPL_TRACE_DEBUG0("read battery level report reference descriptor");
+#endif
+                srvc_uuid = UUID_SERVCLASS_BATTERY;
+                char_uuid = GATT_UUID_BATTERY_LEVEL;
+            }
+            else
+            {
+#if BTA_HH_DEBUG == TRUE
+                APPL_TRACE_DEBUG0("read HID report reference descriptor");
+#endif
+                srvc_uuid = UUID_SERVCLASS_LE_HID;
+                char_uuid = GATT_UUID_HID_REPORT;
+            }
+
+            if (bta_hh_le_read_char_dscrpt(p_dev_cb,
+                                            srvc_uuid,
+                                            BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt->inst_id),
+                                            char_uuid,
+                                            BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt->inst_id),
+                                            GATT_UUID_RPT_REF_DESCR)
+                == BTA_HH_OK)
+            {
+                started = TRUE;
+                break;
+            }
+        }
+        else
+            break;
+
+        if (p_rpt->index == BTA_HH_LE_RPT_MAX - 1)
+            break;
+
+        p_rpt ++;
+    }
+
+
+    /* if no report reference descriptor */
+    if (!started)
+    {
+        /* explore next char */
+        bta_hh_le_search_hid_chars(p_dev_cb);
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_save_rpt_ref
+**
+** Description      save report reference information and move to next one.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_save_rpt_ref(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_LE_RPT  *p_rpt,
+                            tBTA_GATTC_READ *p_data)
+{
+    UINT8 *pp;
+
+    /* if the length of the descriptor value is right, parse it */
+    if (p_data->status == BTA_GATT_OK &&
+        p_data->p_value && p_data->p_value->unformat.len == 2)
+    {
+        pp = p_data->p_value->unformat.p_value;
+
+        STREAM_TO_UINT8(p_rpt->rpt_id, pp);
+        STREAM_TO_UINT8(p_rpt->rpt_type, pp);
+
+        if (p_rpt->rpt_type > BTA_HH_RPTT_FEATURE) /* invalid report type */
+            p_rpt->rpt_type = BTA_HH_RPTT_RESRV;
+
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_DEBUG1("report ID: %d", p_rpt->rpt_id);
+#endif
+    }
+
+    if (p_rpt->index < BTA_HH_LE_RPT_MAX)
+        p_rpt ++;
+
+    /* read next report reference descriptor  */
+    bta_hh_le_read_rpt_ref_descr(p_dev_cb, p_rpt);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_save_rpt_ref
+**
+** Description      save report reference information and move to next one.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_save_ext_rpt_ref(tBTA_HH_DEV_CB *p_dev_cb,
+                                tBTA_GATTC_READ *p_data)
+{
+    UINT8 *pp;
+
+    /* if the length of the descriptor value is right, parse it
+      assume it's a 16 bits UUID */
+    if (p_data->status == BTA_GATT_OK &&
+        p_data->p_value && p_data->p_value->unformat.len == 2)
+    {
+        pp = p_data->p_value->unformat.p_value;
+        STREAM_TO_UINT16(p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].ext_rpt_ref, pp);
+
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_DEBUG1("External Report Reference UUID 0x%04x",
+                    p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].ext_rpt_ref);
+#endif
+    }
+    bta_hh_le_search_hid_chars(p_dev_cb);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_register_input_notif
+**
+** Description      Register for all notifications for the report applicable
+**                  for the protocol mode.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB *p_dev_cb, UINT8 srvc_inst,
+                                    UINT8 proto_mode, BOOLEAN register_ba)
+{
+    tBTA_HH_LE_RPT  *p_rpt = &p_dev_cb->hid_srvc[srvc_inst].report[0];
+    tBTA_GATTC_CHAR_ID  char_id;
+    UINT8   i;
+    UINT16  srvc_uuid;
+
+#if BTA_HH_DEBUG == TRUE
+    APPL_TRACE_DEBUG1("bta_hh_le_register_input_notif mode: %d", proto_mode);
+#endif
+
+    for (i = 0; i < BTA_HH_LE_RPT_MAX; i ++, p_rpt ++)
+    {
+        if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT)
+        {
+            if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL)
+                srvc_uuid = UUID_SERVCLASS_BATTERY;
+            else
+                srvc_uuid = UUID_SERVCLASS_LE_HID;
+
+            bta_hh_le_fill_16bits_srvc_id(TRUE, BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt->inst_id), srvc_uuid, &char_id.srvc_id);
+            bta_hh_le_fill_16bits_char_id(BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt->inst_id), p_rpt->uuid, &char_id.char_id);
+
+            if (register_ba && p_rpt->uuid == GATT_UUID_BATTERY_LEVEL)
+            {
+                BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if,
+                                                   p_dev_cb->addr,
+                                                   &char_id);
+            }
+            /* boot mode, deregister report input notification */
+            else if (proto_mode == BTA_HH_PROTO_BOOT_MODE)
+            {
+                if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+                    p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION)
+                {
+                    APPL_TRACE_DEBUG1("---> Deregister Report ID: %d", p_rpt->rpt_id);
+                    BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if,
+                                                       p_dev_cb->addr,
+                                                       &char_id);
+                }
+                /* register boot reports notification */
+                else if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+                         p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
+                {
+                    APPL_TRACE_DEBUG1("<--- Register Boot Report ID: %d", p_rpt->rpt_id);
+                    BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if,
+                                                       p_dev_cb->addr,
+                                                       &char_id);
+                }
+            }
+            else if (proto_mode == BTA_HH_PROTO_RPT_MODE)
+            {
+                if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+                    p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
+                    p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION)
+                {
+
+                    APPL_TRACE_DEBUG1("---> Deregister Boot Report ID: %d", p_rpt->rpt_id);
+                    BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if,
+                                                       p_dev_cb->addr,
+                                                       &char_id);
+                }
+                else if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+                         p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION)
+                {
+                    APPL_TRACE_DEBUG1("<--- Register Report ID: %d", p_rpt->rpt_id);
+                    BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if,
+                                                       p_dev_cb->addr,
+                                                       &char_id);
+                }
+            }
+            /*
+            else unknow protocol mode */
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_open_cmpl
+**
+** Description      HID over GATT connection sucessfully opened
+**
+*******************************************************************************/
+void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB *p_cb)
+{
+    if ( p_cb->disc_active == BTA_HH_LE_DISC_NONE)
+    {
+#if BTA_HH_DEBUG
+        bta_hh_le_hid_report_dbg(p_cb);
+#endif
+        bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, TRUE);
+        bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+#if (BTA_HH_LE_RECONN == TRUE)
+        if (p_cb->status == BTA_HH_OK)
+        {
+            bta_hh_le_add_dev_bg_conn(p_cb, TRUE);
+        }
+#endif
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_write_char_clt_cfg
+**
+** Description      Utility function to find and write client configuration of
+**                  a characteristic
+**
+*******************************************************************************/
+BOOLEAN bta_hh_le_write_char_clt_cfg(tBTA_HH_DEV_CB *p_cb,
+                                     UINT8 srvc_inst_id, UINT16 srvc_uuid16,
+                                     UINT8 char_inst_id, UINT16 char_uuid16,
+                                     UINT16 clt_cfg_value)
+{
+    tBTA_GATTC_CHAR_ID          char_id;
+    tBT_UUID                    descr_cond;
+    tBTA_GATTC_CHAR_DESCR_ID    descr_id;
+    tBTA_GATT_UNFMT             value;
+    UINT8                      buf[2], *pp = buf;
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst_id, srvc_uuid16, &char_id.srvc_id);
+    bta_hh_le_fill_16bits_char_id(char_inst_id, char_uuid16, &char_id.char_id);
+
+    descr_cond.len       = LEN_UUID_16;
+    descr_cond.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
+
+    value.len = 2;
+    value.p_value = buf;
+
+    UINT16_TO_STREAM(pp, clt_cfg_value);
+
+    if (BTA_GATTC_GetFirstCharDescr(p_cb->conn_id,
+                                    &char_id,
+                                    &descr_cond,
+                                    &descr_id) == BTA_GATT_OK)
+    {
+        BTA_GATTC_WriteCharDescr(p_cb->conn_id,
+                            &descr_id,
+                            BTA_GATTC_TYPE_WRITE_NO_RSP,
+                            &value,
+                            BTA_GATT_AUTH_REQ_NONE);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_write_rpt_clt_cfg
+**
+** Description      write client configuration. This is only for input report
+**                  enable all input notification upon connection open.
+**
+*******************************************************************************/
+BOOLEAN bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst_id)
+{
+    UINT8           i;
+    tBTA_HH_LE_RPT  *p_rpt = &p_cb->hid_srvc[srvc_inst_id].report[p_cb->clt_cfg_idx];
+    UINT16          srvc_uuid;
+
+    for (i = p_cb->clt_cfg_idx; i < BTA_HH_LE_RPT_MAX && p_rpt->in_use; i ++, p_rpt ++)
+    {
+        /* enable notification for all input report, regardless mode */
+        if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT)
+
+        {
+            if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL)
+                srvc_uuid = UUID_SERVCLASS_BATTERY;
+            else
+                srvc_uuid = UUID_SERVCLASS_LE_HID;
+
+            if (bta_hh_le_write_char_clt_cfg(p_cb,
+                                             BTA_HH_LE_RPT_GET_SRVC_INST_ID(p_rpt->inst_id),
+                                             srvc_uuid,
+                                             BTA_HH_LE_RPT_GET_RPT_INST_ID(p_rpt->inst_id),
+                                             p_rpt->uuid,
+                                             BTA_GATT_CLT_CONFIG_NOTIFICATION))
+            {
+                p_cb->clt_cfg_idx = i;
+                return TRUE;
+            }
+        }
+
+    }
+    p_cb->clt_cfg_idx = 0;
+
+    /* client configuration is completed, send open callback */
+    if (p_cb->state == BTA_HH_W4_CONN_ST)
+    {
+        p_cb->disc_active &= ~BTA_HH_LE_DISC_HIDS;
+
+        /* discover scan parameter profile is act as report host */
+        bta_hh_le_search_scps(p_cb);
+    }
+    return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_set_protocol_mode
+**
+** Description      Set remote device protocol mode.
+**
+*******************************************************************************/
+BOOLEAN bta_hh_le_set_protocol_mode(tBTA_HH_DEV_CB *p_cb, tBTA_HH_PROTO_MODE mode)
+{
+    tBTA_GATTC_CHAR_ID  char_id;
+    tBTA_HH_CBDATA      cback_data ;
+    BOOLEAN             exec = TRUE;
+
+    APPL_TRACE_DEBUG1("bta_hh_le_set_protocol_mode attempt mode: %s",
+                      (mode == BTA_HH_PROTO_RPT_MODE)? "Report": "Boot");
+
+    cback_data.handle  = p_cb->hid_handle;
+    /* boot mode is not supported in the remote device */
+    if ((p_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].option_char & BTA_HH_LE_PROTO_MODE_BIT) == 0)
+    {
+        exec        = FALSE;
+        p_cb->mode  = BTA_HH_PROTO_RPT_MODE;
+
+        if (mode == BTA_HH_PROTO_BOOT_MODE)
+        {
+            APPL_TRACE_ERROR0("Set Boot Mode failed!! No PROTO_MODE Char!");
+            cback_data.status = BTA_HH_ERR;
+        }
+        else
+        {
+            /* if set to report mode, need to de-register all input report notification */
+            bta_hh_le_register_input_notif(p_cb, 0, p_cb->mode, FALSE);
+            cback_data.status = BTA_HH_OK;
+        }
+        if (p_cb->state == BTA_HH_W4_CONN_ST)
+        {
+            p_cb->status = (cback_data.status == BTA_HH_OK)? BTA_HH_OK: BTA_HH_ERR_PROTO;
+        }
+        else
+            (* bta_hh_cb.p_cback)(BTA_HH_SET_PROTO_EVT, (tBTA_HH *)&cback_data);
+    }
+    else
+    {
+        bta_hh_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
+        bta_hh_le_fill_16bits_char_id(0, GATT_UUID_HID_PROTO_MODE, &char_id.char_id);
+
+        p_cb->mode = mode;
+        mode = (mode == BTA_HH_PROTO_BOOT_MODE)? BTA_HH_LE_PROTO_BOOT_MODE : BTA_HH_LE_PROTO_REPORT_MODE;
+
+        BTA_GATTC_WriteCharValue(p_cb->conn_id,
+                                 &char_id,
+                                 BTA_GATTC_TYPE_WRITE_NO_RSP,
+                                 1,
+                                 &mode,
+                                 BTA_GATT_AUTH_REQ_NONE);
+    }
+    return exec;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_get_protocol_mode
+**
+** Description      Get remote device protocol mode.
+**
+*******************************************************************************/
+void bta_hh_le_get_protocol_mode(tBTA_HH_DEV_CB *p_cb)
+{
+    tBTA_GATTC_CHAR_ID  char_id;
+    tBTA_HH_HSDATA    hs_data;
+    UINT8 i;
+
+    p_cb->w4_evt = BTA_HH_GET_PROTO_EVT;
+
+    for (i = 0; i< BTA_HH_LE_HID_SRVC_MAX; i ++)
+    {
+        if (p_cb->hid_srvc[i].in_use &&
+            p_cb->hid_srvc[i].option_char & BTA_HH_LE_PROTO_MODE_BIT)
+        {
+            bta_hh_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
+            bta_hh_le_fill_16bits_char_id(0, GATT_UUID_HID_PROTO_MODE, &char_id.char_id);
+
+            BTA_GATTC_ReadCharacteristic(p_cb->conn_id,
+                                        &char_id,
+                                        BTA_GATT_AUTH_REQ_NONE);
+            break;
+        }
+    }
+    /* no service support protocol_mode, by default report mode */
+    if (i == BTA_HH_LE_HID_SRVC_MAX)
+    {
+        hs_data.status  = BTA_HH_OK;
+        hs_data.handle  = p_cb->hid_handle;
+        hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+        p_cb->w4_evt = 0;
+        (* bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH *)&hs_data);
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_expl_rpt
+**
+** Description      explore all report characteristic
+**
+*******************************************************************************/
+void bta_hh_le_expl_rpt(tBTA_HH_DEV_CB *p_dev_cb,
+                           tBTA_GATTC_CHAR_ID *p_char_id,
+                           tBT_UUID *p_char_cond,
+                           tBTA_GATT_CHAR_PROP prop)
+{
+    tBTA_GATTC_CHAR_ID  char_result;
+
+    do
+    {
+        if (bta_hh_le_find_alloc_report_entry(p_dev_cb,
+                                          p_dev_cb->cur_srvc_index,
+                                          GATT_UUID_HID_REPORT,
+                                          p_char_id->char_id.inst_id,
+                                          prop) == NULL)
+        {
+            APPL_TRACE_ERROR0("Add report entry failed !!!")
+            break;
+        }
+
+        APPL_TRACE_DEBUG0("Find more REPORT");
+
+        if (BTA_GATTC_GetNextChar(p_dev_cb->conn_id,
+                          p_char_id,
+                          p_char_cond,
+                          &char_result,
+                          &prop) != BTA_GATT_OK)
+            break;
+
+        p_char_id = &char_result;
+    }
+    while (1);
+
+    APPL_TRACE_ERROR0("all report searched");
+    bta_hh_le_read_rpt_ref_descr(p_dev_cb,
+                                 &p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].report[0]);
+
+
+    return ;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_expl_boot_rpt
+**
+** Description      explore boot report
+**
+*******************************************************************************/
+void bta_hh_le_expl_boot_rpt(tBTA_HH_DEV_CB *p_dev_cb, UINT16 char_uuid,
+                                tBTA_GATT_CHAR_PROP prop)
+{
+    if (bta_hh_le_find_alloc_report_entry(p_dev_cb,
+                                      p_dev_cb->cur_srvc_index,
+                                      char_uuid,
+                                      0,
+                                      prop) == NULL)
+
+    {
+        APPL_TRACE_ERROR0("Add report entry failed !!!")
+    }
+
+    return;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_dis_cback
+**
+** Description      DIS read complete callback
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_dis_cback(BD_ADDR addr, tDIS_VALUE *p_dis_value)
+{
+    tBTA_HH_DEV_CB *p_cb = bta_hh_le_find_dev_cb_by_bda(addr);
+
+
+    if (p_cb == NULL || p_dis_value == NULL)
+    {
+        APPL_TRACE_ERROR0("received unexpected/error DIS callback");
+        return;
+    }
+
+    p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
+    /* plug in the PnP info for this device */
+    if (p_dis_value->attr_mask & DIS_ATTR_PNP_ID_BIT)
+    {
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_DEBUG3("Plug in PnP info: product_id = %02x, vendor_id = %04x, version = %04x",
+                p_dis_value->pnp_id.product_id,
+                p_dis_value->pnp_id.vendor_id,
+                p_dis_value->pnp_id.product_version);
+#endif
+        p_cb->dscp_info.product_id = p_dis_value->pnp_id.product_id;
+        p_cb->dscp_info.vendor_id  = p_dis_value->pnp_id.vendor_id;
+        p_cb->dscp_info.version    = p_dis_value->pnp_id.product_version;
+    }
+    bta_hh_le_open_cmpl(p_cb);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_pri_service_discovery
+**
+** Description      Initialize GATT discovery on the remote LE HID device by opening
+**                  a GATT connection first.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB *p_cb)
+{
+    tBT_UUID        pri_srvc;
+
+    p_cb->disc_active |= (BTA_HH_LE_DISC_HIDS|BTA_HH_LE_DISC_DIS);
+
+    /* read DIS info */
+    if (!DIS_ReadDISInfo(p_cb->addr, bta_hh_le_dis_cback))
+    {
+        APPL_TRACE_ERROR0("read DIS failed");
+        p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
+    }
+
+    /* in parallel */
+    /* start primary service discovery for HID service */
+    pri_srvc.len        = LEN_UUID_16;
+    pri_srvc.uu.uuid16  = UUID_SERVCLASS_LE_HID;
+    BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc);
+    return;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_encrypt_cback
+**
+** Description      link encryption complete callback for bond verification.
+**
+** Returns          None
+**
+*******************************************************************************/
+void bta_hh_le_encrypt_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result)
+{
+    UINT8   idx = bta_hh_find_cb(bd_addr);
+    tBTA_HH_DEV_CB *p_dev_cb;
+
+    APPL_TRACE_ERROR0("bta_hh_le_encrypt_cback");
+
+    if (idx != BTA_HH_IDX_INVALID)
+        p_dev_cb = &bta_hh_cb.kdev[idx];
+    else
+    {
+        APPL_TRACE_ERROR0("unexpected encryption callback, ignore");
+        return;
+    }
+    p_dev_cb->status = (result == BTM_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR_SEC;
+
+    bta_hh_sm_execute(p_dev_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_security_cmpl
+**
+** Description      Security check completed, start the service discovery
+**                  if no cache available, otherwise report connection open completed
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf)
+{
+    if (p_cb->status == BTA_HH_OK)
+    {
+        /*  discovery has been done for HID service */
+        if (p_cb->app_id != 0 && bta_hh_le_hid_srvc_cached(p_cb))
+        {
+            /* configure protocol mode */
+            if (bta_hh_le_set_protocol_mode(p_cb, p_cb->mode) == FALSE)
+            {
+                APPL_TRACE_ERROR0("bta_hh_security_cmpl");
+                bta_hh_le_open_cmpl(p_cb);
+            }
+        }
+        /* start primary service discovery for HID service */
+        else
+        {
+            bta_hh_le_pri_service_discovery(p_cb);
+        }
+    }
+    else
+        bta_hh_le_api_disc_act(p_cb);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_start_security
+**
+** Description      start the security check of the established connection
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_start_security(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf)
+{
+    UINT8           sec_flag=0;
+
+    /* verify bond */
+    BTM_GetSecurityFlags(p_cb->addr, &sec_flag);
+
+    /* if link has been encrypted */
+    if (sec_flag & BTM_SEC_FLAG_ENCRYPTED)
+    {
+        bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+    }
+    /* if bonded and link not encrypted */
+    else if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)
+    {
+        sec_flag = BTM_BLE_SEC_ENCRYPT;
+        p_cb->status = BTA_HH_ERR_AUTH_FAILED;
+        BTM_SetEncryption(p_cb->addr, bta_hh_le_encrypt_cback, &sec_flag);
+    }
+    /* unbonded device, report security error here */
+    else if (p_cb->sec_mask != BTA_SEC_NONE)
+    {
+        sec_flag = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+        p_cb->status = BTA_HH_ERR_AUTH_FAILED;
+        BTM_SetEncryption(p_cb->addr, bta_hh_le_encrypt_cback, &sec_flag);
+    }
+    /* otherwise let it go through */
+    else
+    {
+        bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+    }
+
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_gatt_open
+**
+** Description      process GATT open event.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_gatt_open(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_OPEN *p_data = &p_buf->le_open;
+    UINT8           *p2;
+    tHID_STATUS     status = BTA_HH_ERR;
+
+    /* if received invalid callback data , ignore it */
+    if (p_cb == NULL || p_data == NULL)
+        return;
+
+    p2 = p_data->remote_bda;
+
+    APPL_TRACE_DEBUG3("bta_hh_gatt_open BTA_GATTC_OPEN_EVT bda= [%08x%04x] status =%d",
+                      ((p2[0])<<24)+((p2[1])<<16)+((p2[2])<<8)+(p2[3]),
+                      ((p2[4])<<8)+ p2[5],p_data->status);
+
+    if (p_data->status == BTA_GATT_OK)
+    {
+
+        p_cb->in_use    = TRUE;
+        p_cb->conn_id   = p_data->conn_id;
+        p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+
+        bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_DEBUG3("hid_handle = %2x conn_id = %04x cb_index = %d", p_cb->hid_handle, p_cb->conn_id, p_cb->index);
+#endif
+
+        bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL);
+
+    }
+    else /* open failure */
+    {
+        bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status);
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_close
+**
+** Description      This function process the GATT close event and post it as a
+**                  BTA HH internal event
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_close(tBTA_GATTC_CLOSE * p_data)
+{
+    tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->remote_bda);
+    tBTA_HH_LE_CLOSE    *p_buf = NULL;
+    UINT16  sm_event = BTA_HH_GATT_CLOSE_EVT;
+
+    if (p_dev_cb != NULL &&
+        (p_buf = (tBTA_HH_LE_CLOSE *)GKI_getbuf(sizeof(tBTA_HH_LE_CLOSE))) != NULL)
+    {
+        p_buf->hdr.event            = sm_event;
+        p_buf->hdr.layer_specific   = (UINT16)p_dev_cb->hid_handle;
+        p_buf->conn_id              = p_data->conn_id;
+        p_buf->reason               = p_data->reason;
+
+        p_dev_cb->conn_id           = BTA_GATT_INVALID_CONN_ID;
+
+        bta_sys_sendmsg(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_search_result
+**
+** Description      This function process the GATT service search result.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_search_result(tBTA_GATTC_SRVC_RES *p_srvc_result)
+{
+    tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_srvc_result->conn_id);
+
+    if (p_dev_cb != NULL)
+    {
+        switch (p_srvc_result->service_uuid.id.uuid.uu.uuid16)
+        {
+        case UUID_SERVCLASS_LE_HID:
+            if (p_srvc_result->service_uuid.is_primary)
+            {
+                /* found HID primamry service */
+                /* TODO: proceed to find battery and device info */
+                if (bta_hh_le_add_hid_srvc_entry(p_dev_cb, p_dev_cb->total_srvc))
+                    p_dev_cb->total_srvc ++;
+                APPL_TRACE_DEBUG1("num of hid service: %d", p_dev_cb->total_srvc);
+            }
+            break;
+
+        case UUID_SERVCLASS_SCAN_PARAM : /* scan parameter service */
+            bta_hh_le_search_scps_chars(p_dev_cb);
+            break;
+        }
+
+    }
+
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_gatt_disc_cmpl
+**
+** Description      Check to see if the remote device is a LE only device
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_gatt_disc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_STATUS status)
+{
+    APPL_TRACE_DEBUG0("bta_hh_le_gatt_disc_cmpl ");
+
+    /* if open sucessful or protocol mode not desired, keep the connection open but inform app */
+    if (status == BTA_HH_OK || status == BTA_HH_ERR_PROTO)
+    {
+        /* assign a special APP ID temp, since device type unknown */
+        p_cb->app_id = BTA_HH_APP_ID_LE;
+
+        /* set report notification configuration */
+        p_cb->clt_cfg_idx = 0;
+        bta_hh_le_write_rpt_clt_cfg(p_cb, BTA_HH_LE_SRVC_DEF);
+    }
+    else /* error, close the GATT connection */
+    {
+        /* close GATT connection if it's on */
+        bta_hh_le_api_disc_act(p_cb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_srvc_expl_srvc
+**
+** Description      This function discover the next avaible HID service.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_srvc_expl_srvc(tBTA_HH_DEV_CB *p_dev_cb)
+{
+#if BTA_HH_DEBUG == TRUE
+    APPL_TRACE_DEBUG2("bta_hh_le_srvc_expl_srvc cur_srvc_index = %d in_use = %d",
+                    p_dev_cb->cur_srvc_index,
+                    p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].in_use);
+#endif
+
+    if (p_dev_cb->cur_srvc_index < BTA_HH_LE_HID_SRVC_MAX &&
+        p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].in_use)
+    {
+        if (!p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc)
+            /* explore included service first */
+            {
+                bta_hh_le_search_hid_included(p_dev_cb);
+            }
+        else
+        {
+            /* explore characterisc */
+            p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx = 0;
+            bta_hh_le_search_hid_chars(p_dev_cb);
+        }
+    }
+    else /* all service discvery finished */
+    {
+        bta_hh_le_gatt_disc_cmpl(p_dev_cb, p_dev_cb->status);
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_srvc_search_cmpl
+**
+** Description      This function process the GATT service search complete.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_srvc_search_cmpl(tBTA_GATTC_SEARCH_CMPL *p_data)
+{
+    tBTA_HH_DEV_CB *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+
+    /* service search exception or no HID service is supported on remote */
+    if (p_dev_cb == NULL)
+        return;
+
+    if(p_data->status != BTA_GATT_OK || p_dev_cb->total_srvc == 0)
+    {
+        p_dev_cb->status = BTA_HH_ERR_SDP;
+        /* close the connection and report service discovery complete with error */
+        bta_hh_le_api_disc_act(p_dev_cb);
+    }
+    /* GATT service discovery sucessfully finished */
+    else
+    {
+        if (p_dev_cb->disc_active  & BTA_HH_LE_DISC_SCPS)
+        {
+            p_dev_cb->disc_active  &= ~BTA_HH_LE_DISC_SCPS;
+            bta_hh_le_open_cmpl(p_dev_cb);
+        }
+        else /* discover HID service */
+        {
+        p_dev_cb->cur_srvc_index = 0;
+        bta_hh_le_srvc_expl_srvc(p_dev_cb);
+    }
+}
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_search_hid_included
+**
+** Description      This function search the included service within the HID service.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_le_search_hid_included(tBTA_HH_DEV_CB *p_dev_cb)
+{
+    tBT_UUID    srvc_cond, char_cond;
+    tBTA_GATTC_INCL_SVC_ID  inc_srvc_result;
+    tBTA_GATT_SRVC_ID srvc_id;
+    tBTA_GATTC_CHAR_ID  char_result;
+    tBTA_GATT_CHAR_PROP prop = 0;
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, p_dev_cb->cur_srvc_index, UUID_SERVCLASS_LE_HID, &srvc_id);
+
+    srvc_cond.len = LEN_UUID_16;
+    srvc_cond.uu.uuid16 = UUID_SERVCLASS_BATTERY;
+
+    if (BTA_GATTC_GetFirstIncludedService(p_dev_cb->conn_id,
+                            &srvc_id,
+                            &srvc_cond,
+                            &inc_srvc_result) == BTA_GATT_OK)
+    {
+        /* read include service UUID */
+
+        p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].incl_srvc_inst = inc_srvc_result.incl_svc_id.id.inst_id;
+
+        char_cond.len = LEN_UUID_16;
+        char_cond.uu.uuid16 = GATT_UUID_BATTERY_LEVEL;
+
+        /* find the battery characteristic */
+        if (BTA_GATTC_GetFirstChar( p_dev_cb->conn_id,
+                                    &inc_srvc_result.incl_svc_id,
+                                    &char_cond,
+                                    &char_result,
+                                    &prop) == BTA_GATT_OK)
+        {
+            if (bta_hh_le_find_alloc_report_entry(p_dev_cb,
+                                                  char_result.srvc_id.id.inst_id,
+                                                  GATT_UUID_BATTERY_LEVEL,
+                                                  char_result.char_id.inst_id,
+                                                  prop) == NULL)
+            {
+                APPL_TRACE_ERROR0("Add battery report entry failed !!!")
+            }
+
+            /* read the battery characteristic */
+            BTA_GATTC_ReadCharacteristic(p_dev_cb->conn_id,
+                                         &char_result,
+                                         BTA_GATT_AUTH_REQ_NONE);
+
+            return;
+
+        }
+        else
+        {
+            APPL_TRACE_ERROR0("Remote device does not have battery level");
+        }
+    }
+
+    p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc = TRUE;
+
+    bta_hh_le_srvc_expl_srvc(p_dev_cb);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_read_battery_level_cmpl
+**
+** Description      This function process the battery level read
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_read_battery_level_cmpl(UINT8 status, tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data)
+{
+    p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].expl_incl_srvc = TRUE;
+    bta_hh_le_srvc_expl_srvc(p_dev_cb);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_search_hid_chars
+**
+** Description      This function discover all characteristics a service and
+**                  all descriptors available.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB *p_dev_cb)
+{
+    tBT_UUID    char_cond;
+    tBTA_GATTC_CHAR_ID  char_result;
+    tBTA_GATT_CHAR_PROP prop;
+    BOOLEAN     next = TRUE;
+    UINT16      char_uuid = 0;
+    tBTA_GATT_SRVC_ID srvc_id;
+
+    if (p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx == BTA_HH_LE_DISC_CHAR_NUM ||
+        (p_dev_cb->status != BTA_HH_OK && p_dev_cb->status != BTA_HH_ERR_PROTO))
+    {
+        p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx = 0;
+        /* explore next service */
+        p_dev_cb->cur_srvc_index ++;
+        bta_hh_le_srvc_expl_srvc(p_dev_cb);
+        return;
+    }
+
+    p_dev_cb->hid_srvc[ p_dev_cb->cur_srvc_index].cur_expl_char_idx ++;
+    char_uuid = bta_hh_le_disc_char_uuid[p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].cur_expl_char_idx - 1];
+
+    char_cond.len = LEN_UUID_16;
+    char_cond.uu.uuid16 = char_uuid;
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, p_dev_cb->cur_srvc_index, UUID_SERVCLASS_LE_HID, &srvc_id);
+
+#if BTA_HH_DEBUG == TRUE
+    APPL_TRACE_DEBUG2("bta_hh_le_search_hid_chars: looking for %s(0x%04x)",
+                       bta_hh_uuid_to_str(char_uuid), char_uuid);
+#endif
+
+    if (BTA_GATTC_GetFirstChar( p_dev_cb->conn_id,
+                            &srvc_id,
+                            &char_cond,
+                            &char_result,
+                            &prop) == BTA_GATT_OK)
+    {
+        switch (char_uuid)
+        {
+        case GATT_UUID_HID_CONTROL_POINT:
+            p_dev_cb->hid_srvc[char_result.srvc_id.id.inst_id].option_char |= BTA_HH_LE_CP_BIT;
+            next = TRUE;
+            break;
+        case GATT_UUID_HID_INFORMATION:
+        case GATT_UUID_HID_REPORT_MAP:
+            /* read the char value */
+            BTA_GATTC_ReadCharacteristic(p_dev_cb->conn_id,
+                                        &char_result,
+                                        BTA_GATT_AUTH_REQ_NONE);
+            next = FALSE;
+            break;
+
+        case GATT_UUID_HID_PROTO_MODE:
+            p_dev_cb->hid_srvc[char_result.srvc_id.id.inst_id].option_char |= BTA_HH_LE_PROTO_MODE_BIT;
+            next = !bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
+            break;
+
+        case GATT_UUID_HID_REPORT:
+            bta_hh_le_expl_rpt(p_dev_cb, &char_result, &char_cond, prop);
+            next = FALSE;
+            break;
+
+        /* found boot mode report types */
+        case GATT_UUID_HID_BT_KB_OUTPUT:
+        case GATT_UUID_HID_BT_MOUSE_INPUT:
+        case GATT_UUID_HID_BT_KB_INPUT:
+            bta_hh_le_expl_boot_rpt(p_dev_cb, char_uuid, prop);
+            break;
+        }
+    }
+    else
+    {
+        if (char_uuid == GATT_UUID_HID_PROTO_MODE)
+            next = !bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
+
+    }
+
+    if (next == TRUE)
+    {
+        bta_hh_le_search_hid_chars(p_dev_cb);
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_save_rpt_map
+**
+** Description      save the report map into the control block.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_save_rpt_map(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data)
+{
+    UINT8           *pp ;
+    tBTA_HH_LE_HID_SRVC *p_srvc = &p_dev_cb->hid_srvc[p_data->srvc_id.id.inst_id];
+
+    pp = p_data->p_value->unformat.p_value;
+
+    /* save report descriptor */
+    if (p_srvc->rpt_map != NULL)
+        GKI_freebuf((void*)p_srvc->rpt_map);
+
+    if (p_data->p_value->unformat.len > 0)
+        p_srvc->rpt_map = (UINT8 *)GKI_getbuf(p_data->p_value->unformat.len);
+
+    if (p_srvc->rpt_map != NULL)
+    {
+        STREAM_TO_ARRAY(p_srvc->rpt_map, pp, p_data->p_value->unformat.len);
+        p_srvc->descriptor.dl_len = p_data->p_value->unformat.len;
+        p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc[p_data->srvc_id.id.inst_id].rpt_map;
+    }
+
+    if (bta_hh_le_read_char_dscrpt(p_dev_cb,
+                                   UUID_SERVCLASS_LE_HID,
+                               p_data->srvc_id.id.inst_id,
+                               GATT_UUID_HID_REPORT_MAP,
+                               p_data->char_id.inst_id,
+                               GATT_UUID_EXT_RPT_REF_DESCR) != BTA_HH_OK)
+    {
+        bta_hh_le_search_hid_chars(p_dev_cb);
+    }
+
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_proc_get_rpt_cmpl
+**
+** Description      Process the Read report complete, send GET_REPORT_EVT to application
+**                  with the report data.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_proc_get_rpt_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data)
+{
+    BT_HDR              *p_buf = NULL;
+    tBTA_HH_LE_RPT      *p_rpt;
+    tBTA_HH_HSDATA      hs_data;
+    UINT8               *pp ;
+
+    if (p_dev_cb->w4_evt != BTA_HH_GET_RPT_EVT)
+    {
+        APPL_TRACE_ERROR1("Unexpected READ cmpl, w4_evt = %d", p_dev_cb->w4_evt);
+        return;
+    }
+
+    hs_data.status  = BTA_HH_ERR;
+    hs_data.handle  = p_dev_cb->hid_handle;
+
+    if (p_data->status == BTA_GATT_OK)
+    {
+        p_rpt = bta_hh_le_find_report_entry(p_dev_cb,
+                                            p_data->srvc_id.id.inst_id,//BTA_HH_LE_SRVC_DEF,
+                                            p_data->char_id.uuid.uu.uuid16,
+                                            p_data->char_id.inst_id);
+
+        if (p_rpt != NULL &&
+            p_data->p_value != NULL &&
+            (p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) +p_data->p_value->unformat.len + 1))) != NULL)
+        {
+            /* pack data send to app */
+            hs_data.status  = BTA_HH_OK;
+            p_buf->len = p_data->p_value->unformat.len + 1;
+            p_buf->layer_specific = 0;
+
+            /* attach report ID as the first byte of the report before sending it to USB HID driver */
+            pp = (UINT8*)(p_buf + 1);
+            UINT8_TO_STREAM(pp, p_rpt->rpt_id);
+            memcpy(pp, p_data->p_value->unformat.p_value, p_data->p_value->unformat.len);
+
+            hs_data.rsp_data.p_rpt_data =p_buf;
+        }
+    }
+
+    p_dev_cb->w4_evt = 0;
+    (* bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH *)&hs_data);
+
+    utl_freebuf((void **)&p_buf);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_proc_read_proto_mode
+**
+** Description      Process the Read protocol mode, send GET_PROTO_EVT to application
+**                  with the protocol mode.
+**
+*******************************************************************************/
+void bta_hh_le_proc_read_proto_mode(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ *p_data)
+{
+    tBTA_HH_HSDATA      hs_data;
+
+    hs_data.status  = BTA_HH_ERR;
+    hs_data.handle  = p_dev_cb->hid_handle;
+    hs_data.rsp_data.proto_mode = p_dev_cb->mode;
+
+    if (p_data->status == BTA_GATT_OK && p_data->p_value)
+    {
+        hs_data.status  = BTA_HH_OK;
+        /* match up BTE/BTA report/boot mode def*/
+        hs_data.rsp_data.proto_mode = *(p_data->p_value->unformat.p_value);
+        /* LE repot mode is the opposite value of BR/EDR report mode, flip it here */
+        if (hs_data.rsp_data.proto_mode == 0)
+            hs_data.rsp_data.proto_mode = BTA_HH_PROTO_BOOT_MODE;
+        else
+            hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+
+        p_dev_cb->mode = hs_data.rsp_data.proto_mode;
+    }
+#if BTA_HH_DEBUG
+    APPL_TRACE_DEBUG1("LE GET_PROTOCOL Mode = [%s]",
+                        (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)? "Report" : "Boot");
+#endif
+
+    p_dev_cb->w4_evt = 0;
+    (* bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH *)&hs_data);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_w4_le_read_char_cmpl
+**
+** Description      process the GATT read complete in W4_CONN state.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_w4_le_read_char_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_READ     * p_data = (tBTA_GATTC_READ *)p_buf;
+    UINT8               *pp ;
+
+    if (p_data->char_id.uuid.uu.uuid16 == GATT_UUID_BATTERY_LEVEL)
+    {
+        bta_hh_read_battery_level_cmpl(p_data->status, p_dev_cb, p_data);
+    }
+    else
+    {
+        if (p_data->status == BTA_GATT_OK && p_data->p_value)
+        {
+            pp = p_data->p_value->unformat.p_value;
+
+            switch (p_data->char_id.uuid.uu.uuid16)
+            {
+           /* save device information */
+            case GATT_UUID_HID_INFORMATION:
+                STREAM_TO_UINT16(p_dev_cb->dscp_info.version, pp);
+                STREAM_TO_UINT8(p_dev_cb->dscp_info.ctry_code, pp);
+                STREAM_TO_UINT8(p_dev_cb->dscp_info.flag, pp);
+                break;
+
+            case GATT_UUID_HID_REPORT_MAP:
+                bta_hh_le_save_rpt_map(p_dev_cb, p_data);
+                return;
+
+            default:
+#if BTA_HH_DEBUG == TRUE
+                APPL_TRACE_ERROR2("Unexpected read %s(0x%04x)",
+                                bta_hh_uuid_to_str(p_data->char_id.uuid.uu.uuid16),
+                                p_data->char_id.uuid.uu.uuid16);
+#endif
+                break;
+            }
+        }
+        else
+        {
+#if BTA_HH_DEBUG == TRUE
+            APPL_TRACE_ERROR3("read uuid %s[0x%04x] error: %d",
+                                bta_hh_uuid_to_str(p_data->char_id.uuid.uu.uuid16),
+                                p_data->char_id.uuid.uu.uuid16,
+                                p_data->status);
+#else
+            APPL_TRACE_ERROR2("read uuid [0x%04x] error: %d", p_data->char_id.uuid.uu.uuid16, p_data->status);
+#endif
+        }
+        bta_hh_le_search_hid_chars(p_dev_cb);
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_read_char_cmpl
+**
+** Description      a characteristic value is received.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_read_char_cmpl (tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf;
+
+    switch (p_data->char_id.uuid.uu.uuid16)
+    {
+    /* GET_REPORT */
+    case GATT_UUID_HID_REPORT:
+    case GATT_UUID_HID_BT_KB_INPUT:
+    case GATT_UUID_HID_BT_KB_OUTPUT:
+    case GATT_UUID_HID_BT_MOUSE_INPUT:
+    case GATT_UUID_BATTERY_LEVEL: /* read battery level */
+        bta_hh_le_proc_get_rpt_cmpl(p_dev_cb, p_data);
+        break;
+
+    case GATT_UUID_HID_PROTO_MODE:
+        bta_hh_le_proc_read_proto_mode(p_dev_cb, p_data);
+        break;
+
+    default:
+        APPL_TRACE_ERROR1("Unexpected Read UUID: 0x%04x", p_data->char_id.uuid.uu.uuid16);
+        break;
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_read_descr_cmpl
+**
+** Description      read characteristic descriptor is completed in CONN st.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_HH_LE_RPT  *p_rpt;
+    tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf;
+    UINT8   *pp;
+
+    /* if a report client configuration */
+    if (p_data->descr_type.uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG)
+    {
+        if ((p_rpt = bta_hh_le_find_report_entry(p_dev_cb,
+                                                 BTA_HH_LE_SRVC_DEF,
+                                                 p_data->char_id.uuid.uu.uuid16,
+                                                 p_data->char_id.inst_id)) != NULL)
+        {
+            pp = p_data->p_value->unformat.p_value;
+            STREAM_TO_UINT16(p_rpt->client_cfg_value, pp);
+
+            APPL_TRACE_DEBUG1("Read Client Configuration: 0x%04x", p_rpt->client_cfg_value);
+        }
+    }
+}
+
+void bta_hh_le_read_battery_level_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATTC_READ * p_data)
+{
+    tBTA_HH_LE_RPT  *p_rpt;
+    UINT16 descr_uuid = p_data->descr_type.uuid.uu.uuid16;
+
+    /* read report reference descriptor for battery level is completed */
+    if (descr_uuid == GATT_UUID_RPT_REF_DESCR)
+    {
+        if ((p_rpt = bta_hh_le_find_report_entry(p_dev_cb,
+                                            p_data->srvc_id.id.inst_id,
+                                            GATT_UUID_BATTERY_LEVEL,
+                                            p_data->char_id.inst_id)) == NULL)
+        {
+            bta_hh_le_search_hid_chars(p_dev_cb);
+        }
+        else
+            bta_hh_le_save_rpt_ref(p_dev_cb, p_rpt, p_data);
+
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_w4_le_read_descr_cmpl
+**
+** Description      read characteristic descriptor is completed in W4_CONN st.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_w4_le_read_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_HH_LE_RPT  *p_rpt;
+    tBTA_GATTC_READ * p_data = (tBTA_GATTC_READ *)p_buf;
+    UINT16 char_uuid16;
+
+    if (p_data == NULL)
+        return;
+
+    char_uuid16 = p_data->char_id.uuid.uu.uuid16;
+
+#if BTA_HH_DEBUG == TRUE
+    APPL_TRACE_DEBUG2("bta_hh_w4_le_read_descr_cmpl uuid: %s(0x%04x)",
+                        bta_hh_uuid_to_str(p_data->descr_type.uuid.uu.uuid16),
+                        p_data->descr_type.uuid.uu.uuid16);
+#endif
+    switch (char_uuid16)
+    {
+    case GATT_UUID_HID_REPORT:
+        if ((p_rpt = bta_hh_le_find_report_entry(p_dev_cb,
+                                            p_data->srvc_id.id.inst_id,
+                                            GATT_UUID_HID_REPORT,
+                                            p_data->char_id.inst_id)) == NULL)
+        {
+            bta_hh_le_search_hid_chars(p_dev_cb);
+        }
+        else
+            bta_hh_le_save_rpt_ref(p_dev_cb, p_rpt, p_data);
+        break;
+
+    case GATT_UUID_HID_REPORT_MAP:
+        bta_hh_le_save_ext_rpt_ref(p_dev_cb, p_data);
+        break;
+
+    case GATT_UUID_BATTERY_LEVEL:
+        bta_hh_le_read_battery_level_descr_cmpl(p_dev_cb, p_data);
+        break;
+
+    default:
+        APPL_TRACE_ERROR1("unknown descriptor read complete for uuid: 0x%04x", char_uuid16);
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_w4_le_write_cmpl
+**
+** Description      Write charactersitic complete event at W4_CONN st.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_w4_le_write_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_WRITE    *p_data = (tBTA_GATTC_WRITE *)p_buf;
+
+    if (p_data == NULL)
+        return;
+
+    if (p_data->char_id.uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE)
+    {
+        p_dev_cb->status = (p_data->status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
+
+        if ((p_dev_cb->disc_active & BTA_HH_LE_DISC_HIDS) != 0)
+        {
+            bta_hh_le_search_hid_chars(p_dev_cb);
+        }
+        else
+        {
+            bta_hh_le_open_cmpl(p_dev_cb);
+        }
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_write_cmpl
+**
+** Description      Write charactersitic complete event at CONN st.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_write_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_WRITE    *p_data = (tBTA_GATTC_WRITE *)p_buf;
+    tBTA_HH_CBDATA      cback_data ;
+    UINT16              cb_evt = p_dev_cb->w4_evt;
+
+    if (p_data == NULL  || cb_evt == 0)
+        return;
+
+#if BTA_HH_DEBUG
+    APPL_TRACE_DEBUG1("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
+#endif
+    switch (p_data->char_id.uuid.uu.uuid16)
+    {
+    /* Set protocol finished */
+    case GATT_UUID_HID_PROTO_MODE:
+        cback_data.handle  = p_dev_cb->hid_handle;
+        if (p_data->status == BTA_GATT_OK)
+        {
+            bta_hh_le_register_input_notif(p_dev_cb, p_data->srvc_id.id.inst_id, p_dev_cb->mode, FALSE);
+            cback_data.status = BTA_HH_OK;
+        }
+        else
+            cback_data.status =  BTA_HH_ERR;
+        p_dev_cb->w4_evt = 0;
+        (* bta_hh_cb.p_cback)(cb_evt, (tBTA_HH *)&cback_data);
+        break;
+
+    /* Set Report finished */
+    case GATT_UUID_HID_REPORT:
+    case GATT_UUID_HID_BT_KB_INPUT:
+    case GATT_UUID_HID_BT_MOUSE_INPUT:
+    case GATT_UUID_HID_BT_KB_OUTPUT:
+        cback_data.handle  = p_dev_cb->hid_handle;
+        cback_data.status = (p_data->status == BTA_GATT_OK)? BTA_HH_OK : BTA_HH_ERR;
+        p_dev_cb->w4_evt = 0;
+        (* bta_hh_cb.p_cback)(cb_evt, (tBTA_HH *)&cback_data);
+        break;
+
+    case GATT_UUID_SCAN_INT_WINDOW:
+        bta_hh_le_register_scpp_notif(p_dev_cb, p_data->status);
+        break;
+
+
+    default:
+        break;
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_write_char_descr_cmpl
+**
+** Description      Write charactersitic descriptor complete event
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_write_char_descr_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_WRITE    *p_data = (tBTA_GATTC_WRITE *)p_buf;
+    UINT8   srvc_inst_id, hid_inst_id;
+
+    /* only write client configuration possible */
+    if (p_data && p_data->descr_type.uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG)
+    {
+        srvc_inst_id = p_data->srvc_id.id.inst_id;
+        hid_inst_id = srvc_inst_id;
+        switch (p_data->char_id.uuid.uu.uuid16)
+        {
+        case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */
+            hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(p_dev_cb, srvc_inst_id);
+            /* fall through */
+        case GATT_UUID_HID_BT_KB_INPUT:
+        case GATT_UUID_HID_BT_MOUSE_INPUT:
+        case GATT_UUID_HID_REPORT:
+            if (p_data->status == BTA_GATT_OK)
+                p_dev_cb->hid_srvc[hid_inst_id].report[p_dev_cb->clt_cfg_idx ++].client_cfg_value =
+                        BTA_GATT_CLT_CONFIG_NOTIFICATION;
+
+            bta_hh_le_write_rpt_clt_cfg(p_dev_cb, hid_inst_id);
+
+            break;
+
+        case GATT_UUID_SCAN_REFRESH:
+            bta_hh_le_register_scpp_notif_cmpl(p_dev_cb, p_data->status);
+            break;
+        default:
+            APPL_TRACE_ERROR1("Unknown char ID clt cfg: 0x%04x", p_data->char_id.uuid.uu.uuid16);
+        }
+    }
+    else
+    {
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_ERROR2("Unexpected write to %s(0x%04x)",
+                        bta_hh_uuid_to_str(p_data->descr_type.uuid.uu.uuid16),
+                        p_data->descr_type.uuid.uu.uuid16);
+#else
+        APPL_TRACE_ERROR1("Unexpected write to (0x%04x)", p_data->descr_type.uuid.uu.uuid16);
+#endif
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_input_rpt_notify
+**
+** Description      process the notificaton event, most likely for input report.
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY *p_data)
+{
+    tBTA_HH_DEV_CB       *p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+    UINT8           app_id;
+    UINT8           *p_buf;
+    tBTA_HH_LE_RPT  *p_rpt;
+
+    if (p_dev_cb == NULL)
+    {
+        APPL_TRACE_ERROR0("notification received from Unknown device");
+        return;
+    }
+
+    app_id= p_dev_cb->app_id;
+
+    p_rpt = bta_hh_le_find_report_entry(p_dev_cb,
+                                        BTA_HH_LE_SRVC_DEF,
+                                        p_data->char_id.char_id.uuid.uu.uuid16,
+                                        p_data->char_id.char_id.inst_id);
+    if (p_rpt == NULL)
+    {
+        APPL_TRACE_ERROR0("notification received for Unknown Report");
+        return;
+    }
+
+    if (p_data->char_id.char_id.uuid.uu.uuid16 == GATT_UUID_HID_BT_MOUSE_INPUT)
+        app_id = BTA_HH_APP_ID_MI;
+    else if (p_data->char_id.char_id.uuid.uu.uuid16 == GATT_UUID_HID_BT_KB_INPUT)
+        app_id = BTA_HH_APP_ID_KB;
+
+    /* need to append report ID to the head of data */
+    if ((p_buf = (UINT8 *)GKI_getbuf((UINT16)(p_data->len + 1))) == NULL)
+    {
+        APPL_TRACE_ERROR0("No resources to send report data");
+        return;
+    }
+
+    APPL_TRACE_ERROR1("Notification received on report ID: %d", p_rpt->rpt_id);
+
+    p_buf[0] = p_rpt->rpt_id;
+    memcpy(&p_buf[1], p_data->value, p_data->len);
+    p_data->len ++;
+
+    bta_hh_co_data((UINT8)p_dev_cb->hid_handle,
+                    p_buf,
+                    p_data->len,
+                    p_dev_cb->mode,
+                    0 , /* no sub class*/
+                    p_dev_cb->dscp_info.ctry_code,
+                    p_dev_cb->addr,
+                    app_id);
+
+    GKI_freebuf(p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         bta_hh_gatt_open_fail
+**
+** Description      action function to process the open fail
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_open_fail(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+    tBTA_HH_CONN            conn_dat ;
+    tBTA_HH_LE_HID_SRVC     *p_hid_srvc = &p_cb->hid_srvc[0];
+    UINT8   i;
+
+    p_cb->disc_active = BTA_HH_LE_DISC_NONE;
+    /* Failure in opening connection or GATT discovery failure */
+    conn_dat.handle = p_cb->hid_handle;
+    memcpy(conn_dat.bda, p_cb->addr, BD_ADDR_LEN);
+    conn_dat.le_hid = TRUE;
+    conn_dat.scps_supported = p_cb->scps_supported;
+
+    if (p_cb->status == BTA_HH_OK)
+        conn_dat.status = (p_data->le_close.reason == BTA_GATT_CONN_UNKNOWN) ? p_cb->status : BTA_HH_ERR;
+    else
+        conn_dat.status = p_cb->status;
+
+    for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++, p_hid_srvc ++)
+    {
+        utl_freebuf((void **)&p_hid_srvc->rpt_map);
+        memset(p_hid_srvc, 0, sizeof(tBTA_HH_LE_HID_SRVC));
+    }
+
+    /* Report OPEN fail event */
+    (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_gatt_close
+**
+** Description      action function to process the GATT close int he state machine.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_gatt_close(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+    tBTA_HH_CBDATA          disc_dat = {BTA_HH_OK, 0};
+
+    /* finaliza device driver */
+    bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+    /* update total conn number */
+    bta_hh_cb.cnt_num --;
+
+    disc_dat.handle = p_cb->hid_handle;
+    disc_dat.status = p_cb->status;
+
+    (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat);
+
+    /* if no connection is active and HH disable is signaled, disable service */
+    if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable)
+    {
+        bta_hh_disc_cmpl();
+    }
+    else
+    {
+#if (BTA_HH_LE_RECONN == TRUE)
+    if (p_data->le_close.reason == BTA_GATT_CONN_TIMEOUT)
+    {
+        bta_hh_le_add_dev_bg_conn(p_cb, FALSE);
+    }
+#endif
+    }
+
+    return;
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_api_disc_act
+**
+** Description      initaite a Close API to a remote HID device
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB *p_cb)
+{
+    if (p_cb->conn_id != BTA_GATT_INVALID_CONN_ID)
+        BTA_GATTC_Close(p_cb->conn_id);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_get_rpt
+**
+** Description      GET_REPORT on a LE HID Report
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_get_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id)
+{
+    tBTA_HH_LE_RPT  *p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id);
+    tBTA_GATTC_CHAR_ID  char_id;
+    UINT16  srvc_uuid = UUID_SERVCLASS_LE_HID;
+
+    if (p_rpt == NULL)
+    {
+        APPL_TRACE_ERROR0("bta_hh_le_get_rpt: no matching report");
+        return;
+    }
+    if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL)
+        srvc_uuid = UUID_SERVCLASS_BATTERY;
+
+    p_cb->w4_evt = BTA_HH_GET_RPT_EVT;
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, srvc_uuid, &char_id.srvc_id);
+    bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id);
+
+    BTA_GATTC_ReadCharacteristic(p_cb->conn_id,
+                                 &char_id,
+                                 BTA_GATT_AUTH_REQ_NONE);
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_write_rpt
+**
+** Description      SET_REPORT/or DATA output on a LE HID Report
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst,
+                         tBTA_GATTC_WRITE_TYPE   write_type,
+                         tBTA_HH_RPT_TYPE r_type,
+                         BT_HDR *p_buf, UINT16 w4_evt )
+{
+    tBTA_HH_LE_RPT  *p_rpt;
+    tBTA_GATTC_CHAR_ID  char_id;
+    UINT8   *p_value, rpt_id;
+
+    if (p_buf == NULL || p_buf->len == 0)
+    {
+        APPL_TRACE_ERROR0("bta_hh_le_write_rpt: Illegal data");
+        return;
+    }
+
+    /* strip report ID from the data */
+    p_value = (UINT8 *)(p_buf + 1) + p_buf->offset;
+    STREAM_TO_UINT8(rpt_id, p_value);
+    p_buf->len -= 1;
+
+    p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id);
+
+    if (p_rpt == NULL)
+    {
+        APPL_TRACE_ERROR0("bta_hh_le_write_rpt: no matching report");
+        return;
+    }
+
+    APPL_TRACE_ERROR2("bta_hh_le_write_rpt: ReportID: 0x%02x Data Len: %d", rpt_id, p_buf->len);
+
+    p_cb->w4_evt = w4_evt;
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
+    bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id);
+
+    BTA_GATTC_WriteCharValue(p_cb->conn_id,
+                             &char_id,
+                             write_type, /* default to use write request */
+                             p_buf->len,
+                             p_value,
+                             BTA_GATT_AUTH_REQ_NONE);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_suspend
+**
+** Description      send LE suspend or exit suspend mode to remote device.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_suspend(tBTA_HH_DEV_CB *p_cb, tBTA_HH_TRANS_CTRL_TYPE ctrl_type)
+{
+    UINT8 i;
+    tBTA_GATTC_CHAR_ID  char_id;
+
+    ctrl_type -= BTA_HH_CTRL_SUSPEND;
+
+    for (i = 0; i < BTA_HH_LE_HID_SRVC_MAX; i ++)
+    {
+        bta_hh_le_fill_16bits_srvc_id(TRUE, i, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
+        bta_hh_le_fill_16bits_char_id(0, GATT_UUID_HID_CONTROL_POINT, &char_id.char_id);
+
+        BTA_GATTC_WriteCharValue(p_cb->conn_id,
+                                 &char_id,
+                                 BTA_GATTC_TYPE_WRITE_NO_RSP, /* default to use write request */
+                                 1,
+                                 &ctrl_type,
+                                 BTA_GATT_AUTH_REQ_NONE);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_write_dev_act
+**
+** Description      Write LE device action. can be SET/GET/DATA transaction.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
+{
+    switch(p_data->api_sndcmd.t_type)
+    {
+        case HID_TRANS_SET_PROTOCOL:
+            p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
+            bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param);
+            break;
+
+        case HID_TRANS_GET_PROTOCOL:
+            bta_hh_le_get_protocol_mode(p_cb);
+            break;
+
+        case HID_TRANS_GET_REPORT:
+            bta_hh_le_get_rpt(p_cb,
+                              BTA_HH_LE_SRVC_DEF,
+                              p_data->api_sndcmd.param,
+                              p_data->api_sndcmd.rpt_id);
+            break;
+
+        case HID_TRANS_SET_REPORT:
+            bta_hh_le_write_rpt(p_cb,
+                                BTA_HH_LE_SRVC_DEF,
+                                BTA_GATTC_TYPE_WRITE,
+                                p_data->api_sndcmd.param,
+                                p_data->api_sndcmd.p_data,
+                                BTA_HH_SET_RPT_EVT);
+            break;
+
+        case HID_TRANS_DATA:  /* output report */
+
+            bta_hh_le_write_rpt(p_cb,
+                                BTA_HH_LE_SRVC_DEF,
+                                BTA_GATTC_TYPE_WRITE_NO_RSP,
+                                p_data->api_sndcmd.param,
+                                p_data->api_sndcmd.p_data,
+                                BTA_HH_DATA_EVT);
+            break;
+
+        case HID_TRANS_CONTROL:
+            /* no handshake event will be generated */
+            /* if VC_UNPLUG is issued, set flag */
+            if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND ||
+                p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
+            {
+                bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param);
+            }
+            break;
+
+        default:
+            APPL_TRACE_ERROR1("unsupported trsanction for LE HID device: %d", p_data->api_sndcmd.t_type);
+            break;
+    }
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_get_dscp_act
+**
+** Description      Send ReportDescriptor to application for all HID services.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB *p_cb)
+{
+    UINT8 i;
+
+    for (i = 0 ;i < BTA_HH_LE_HID_SRVC_MAX; i ++)
+    {
+        if (p_cb->hid_srvc[i].in_use)
+        {
+            p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc[i].descriptor.dl_len;
+            p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc[i].descriptor.dsc_list;
+
+            (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info);
+        }
+        else
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_add_dev_bg_conn
+**
+** Description      Remove a LE HID device from back ground connection procedure.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond)
+{
+    UINT8           sec_flag=0;
+    BOOLEAN         to_add = TRUE;
+
+    if (check_bond)
+    {
+        /* start reconnection if remote is a bonded device */
+        /* verify bond */
+        BTM_GetSecurityFlags(p_cb->addr, &sec_flag);
+
+        if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) == 0)
+            to_add = FALSE;
+    }
+
+    if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/
+        !p_cb->in_bg_conn && to_add)
+    {
+        /* add device into BG connection to accept remote initiated connection */
+        BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE);
+        p_cb->in_bg_conn = TRUE;
+
+        BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL);
+    }
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_add_device
+**
+** Description      Add a LE HID device as a known device, and also add the address
+**                  into back ground connection WL for incoming connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info)
+{
+
+    /* update DI information */
+    bta_hh_update_di_info(p_cb,
+                          p_dev_info->dscp_info.vendor_id,
+                          p_dev_info->dscp_info.product_id,
+                          p_dev_info->dscp_info.version,
+                          p_dev_info->dscp_info.flag);
+
+    /* add to BTA device list */
+    bta_hh_add_device_to_list(p_cb, p_cb->hid_handle,
+                              p_dev_info->attr_mask,
+                              &p_dev_info->dscp_info.descriptor,
+                              p_dev_info->sub_class,
+                              p_dev_info->dscp_info.ssr_max_latency,
+                              p_dev_info->dscp_info.ssr_min_tout,
+                              p_dev_info->app_id);
+
+    bta_hh_le_add_dev_bg_conn(p_cb, FALSE);
+
+    return p_cb->hid_handle;
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_remove_dev_bg_conn
+**
+** Description      Remove a LE HID device from back ground connection procedure.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB *p_dev_cb)
+{
+    if (p_dev_cb->in_bg_conn)
+    {
+        p_dev_cb->in_bg_conn = FALSE;
+
+        BTA_GATTC_CancelOpen(bta_hh_cb.gatt_if, p_dev_cb->addr, FALSE);
+    }
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_update_scpp
+**
+** Description      action function to update the scan parameters on remote HID
+**                  device
+**
+** Parameters:
+**
+*******************************************************************************/
+void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_dev_cb, tBTA_HH_DATA *p_buf)
+{
+    tBTA_GATTC_CHAR_ID  char_id;
+    UINT8   value[4], *p = value;
+    tBTA_HH_CBDATA      cback_data ;
+
+    if (!p_dev_cb->is_le_device ||
+        p_dev_cb->mode != BTA_HH_PROTO_RPT_MODE ||
+        p_dev_cb->scps_supported == FALSE)
+    {
+        APPL_TRACE_ERROR0("Can not set ScPP scan paramter as boot host, or remote does not support ScPP ");
+
+        cback_data.handle = p_dev_cb->hid_handle;
+        cback_data.status = BTA_HH_ERR;
+        (* bta_hh_cb.p_cback)(BTA_HH_UPDATE_SCPP_EVT, (tBTA_HH *)&cback_data);
+
+        return;
+    }
+
+    p_dev_cb->w4_evt = BTA_HH_UPDATE_SCPP_EVT;
+
+    UINT16_TO_STREAM(p, p_buf->le_scpp_update.scan_int);
+    UINT16_TO_STREAM(p, p_buf->le_scpp_update.scan_win);
+
+    bta_hh_le_fill_16bits_srvc_id(TRUE, BTA_HH_SCPP_INST_DEF, UUID_SERVCLASS_SCAN_PARAM, &char_id.srvc_id);
+    bta_hh_le_fill_16bits_char_id(BTA_HH_SCPP_INST_DEF, GATT_UUID_SCAN_INT_WINDOW, &char_id.char_id);
+
+    BTA_GATTC_WriteCharValue(p_dev_cb->conn_id,
+                             &char_id,
+                             BTA_GATTC_TYPE_WRITE_NO_RSP,
+                             2,
+                             value,
+                             BTA_GATT_AUTH_REQ_NONE);
+
+}
+/*******************************************************************************
+**
+** Function         bta_hh_gattc_callback
+**
+** Description      This is GATT client callback function used in BTA HH.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
+{
+    tBTA_HH_DEV_CB *p_dev_cb;
+    UINT16          evt;
+#if BTA_HH_DEBUG
+    APPL_TRACE_DEBUG1("bta_hh_gattc_callback event = %d", event);
+#endif
+    if (p_data == NULL)
+        return;
+
+    switch (event)
+    {
+        case BTA_GATTC_REG_EVT: /* 0 */
+            bta_hh_le_register_cmpl(&p_data->reg_oper);
+            break;
+
+        case BTA_GATTC_DEREG_EVT: /* 1 */
+            bta_hh_cleanup_disable(p_data->reg_oper.status);
+            break;
+
+        case BTA_GATTC_OPEN_EVT: /* 2 */
+            p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->open.remote_bda);
+            bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_OPEN_EVT, (tBTA_HH_DATA *)&p_data->open);
+            break;
+
+        case BTA_GATTC_READ_CHAR_EVT: /* 3 */
+        case BTA_GATTC_READ_DESCR_EVT: /* 8 */
+            p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->read.conn_id);
+            if (event == BTA_GATTC_READ_CHAR_EVT)
+                evt = BTA_HH_GATT_READ_CHAR_CMPL_EVT;
+            else
+                evt = BTA_HH_GATT_READ_DESCR_CMPL_EVT;
+
+            bta_hh_sm_execute(p_dev_cb, evt, (tBTA_HH_DATA *)&p_data->read);
+            break;
+
+        case BTA_GATTC_WRITE_DESCR_EVT: /* 9 */
+        case BTA_GATTC_WRITE_CHAR_EVT: /* 4 */
+            p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->write.conn_id);
+            if (event == BTA_GATTC_WRITE_CHAR_EVT)
+                evt = BTA_HH_GATT_WRITE_CHAR_CMPL_EVT;
+            else
+                evt = BTA_HH_GATT_WRITE_DESCR_CMPL_EVT;
+
+            bta_hh_sm_execute(p_dev_cb, evt, (tBTA_HH_DATA *)&p_data->write);
+            break;
+
+        case BTA_GATTC_CLOSE_EVT: /* 5 */
+            bta_hh_le_close(&p_data->close);
+            break;
+
+        case BTA_GATTC_SEARCH_CMPL_EVT: /* 6 */
+            bta_hh_le_srvc_search_cmpl(&p_data->search_cmpl);
+            break;
+
+        case BTA_GATTC_SEARCH_RES_EVT: /* 7 */
+            bta_hh_le_search_result(&p_data->srvc_res);
+            break;
+
+
+
+        case BTA_GATTC_NOTIF_EVT: /* 10 */
+            bta_hh_le_input_rpt_notify(&p_data->notify);
+            break;
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_hid_read_rpt_clt_cfg
+**
+** Description      a test command to read report descriptor client configuration
+**
+** Returns          void
+**
+*******************************************************************************/
+void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id)
+{
+    tBTA_HH_DEV_CB *p_cb = NULL;
+    tBTA_HH_LE_RPT *p_rpt ;
+    UINT8           index = BTA_HH_IDX_INVALID;
+
+    index = bta_hh_find_cb(bd_addr);
+    if ((index = bta_hh_find_cb(bd_addr))== BTA_HH_IDX_INVALID)
+    {
+        APPL_TRACE_ERROR0("unknown device");
+        return;
+    }
+
+    p_cb = &bta_hh_cb.kdev[index];
+
+    p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[BTA_HH_LE_SRVC_DEF].report, p_cb->mode, BTA_HH_RPTT_INPUT, rpt_id);
+
+    if (p_rpt == NULL)
+    {
+        APPL_TRACE_ERROR0("bta_hh_le_write_rpt: no matching report");
+        return;
+    }
+
+    bta_hh_le_read_char_dscrpt(p_cb,
+                               UUID_SERVCLASS_LE_HID,
+                               BTA_HH_LE_SRVC_DEF,
+                               p_rpt->uuid,
+                               p_rpt->inst_id,
+                               GATT_UUID_CHAR_CLIENT_CONFIG);
+
+
+
+    return;
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_search_scps
+**
+** Description      discovery scan parameter service if act as report host, otherwise
+**                  finish LE connection.
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_le_search_scps(tBTA_HH_DEV_CB *p_cb)
+{
+    tBT_UUID        pri_srvc;
+
+    if ( p_cb->mode == BTA_HH_PROTO_RPT_MODE)
+    {
+        p_cb->disc_active  |= BTA_HH_LE_DISC_SCPS;
+        /* start  service discovery for Scan Parameter service */
+        pri_srvc.len        = LEN_UUID_16;
+        pri_srvc.uu.uuid16  = UUID_SERVCLASS_SCAN_PARAM;
+
+        BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc);
+    }
+    else
+        bta_hh_le_open_cmpl(p_cb);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_search_scps_chars
+**
+** Description      find ScPS optional characteristics scan refresh
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_le_search_scps_chars(tBTA_HH_DEV_CB *p_cb)
+{
+    tBTA_GATT_SRVC_ID   srvc_id;
+    tBT_UUID            char_cond;
+    tBTA_GATTC_CHAR_ID  char_result;
+    tBTA_GATT_CHAR_PROP prop;
+
+    p_cb->scps_supported = TRUE;
+    bta_hh_le_fill_16bits_srvc_id(TRUE, 0, UUID_SERVCLASS_SCAN_PARAM, &srvc_id);
+
+    char_cond.len   = LEN_UUID_16;
+    char_cond.uu.uuid16 = GATT_UUID_SCAN_REFRESH;
+
+    /* look for scan refresh */
+    if (BTA_GATTC_GetFirstChar( p_cb->conn_id,
+                                &srvc_id,
+                                &char_cond,
+                                &char_result,
+                                &prop) == BTA_GATT_OK)
+    {
+        if (prop & BTA_GATT_CHAR_PROP_BIT_NOTIFY)
+            p_cb->scps_notify |= BTA_HH_LE_SCPS_NOTIFY_SPT;
+        else
+            p_cb->scps_notify = BTA_HH_LE_SCPS_NOTIFY_NONE;
+
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bta_hh_le_register_scpp_notif
+**
+** Description      register scan parameter refresh notitication complete
+**
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_le_register_scpp_notif(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status)
+{
+    UINT8               sec_flag=0;
+    tBTA_GATTC_CHAR_ID  char_id;
+
+    /* if write scan parameter sucessful */
+    /* if bonded and notification is not enabled, configure the client configuration */
+    if (status == BTA_GATT_OK &&
+        (p_dev_cb->scps_notify & BTA_HH_LE_SCPS_NOTIFY_SPT) != 0 &&
+        (p_dev_cb->scps_notify & BTA_HH_LE_SCPS_NOTIFY_ENB) == 0)
+    {
+        BTM_GetSecurityFlags(p_dev_cb->addr, &sec_flag);
+        if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN))
+        {
+            if (bta_hh_le_write_char_clt_cfg (p_dev_cb,
+                                              BTA_HH_SCPP_INST_DEF,
+                                              UUID_SERVCLASS_SCAN_PARAM,
+                                              BTA_HH_SCPP_INST_DEF,
+                                              GATT_UUID_SCAN_REFRESH,
+                                              BTA_GATT_CLT_CONFIG_NOTIFICATION))
+            {
+                bta_hh_le_fill_16bits_srvc_id(TRUE, BTA_HH_SCPP_INST_DEF, UUID_SERVCLASS_SCAN_PARAM, &char_id.srvc_id);
+                bta_hh_le_fill_16bits_char_id(BTA_HH_SCPP_INST_DEF, GATT_UUID_SCAN_REFRESH, &char_id.char_id);
+
+                BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if,
+                                                   p_dev_cb->addr,
+                                                   &char_id);
+                return;
+            }
+        }
+    }
+    bta_hh_le_register_scpp_notif_cmpl(p_dev_cb, status);
+}
+/*******************************************************************************
+**
+** Function         bta_hh_le_register_scpp_notif_cmpl
+**
+** Description      action function to register scan parameter refresh notitication
+**
+** Parameters:
+**
+*******************************************************************************/
+static void bta_hh_le_register_scpp_notif_cmpl(tBTA_HH_DEV_CB *p_dev_cb, tBTA_GATT_STATUS status)
+{
+    tBTA_HH_CBDATA      cback_data ;
+    UINT16              cb_evt = p_dev_cb->w4_evt;
+
+    if (status == BTA_GATT_OK)
+        p_dev_cb->scps_notify = (BTA_HH_LE_SCPS_NOTIFY_ENB | BTA_HH_LE_SCPS_NOTIFY_SPT);
+
+    cback_data.handle  = p_dev_cb->hid_handle;
+    cback_data.status = (status == BTA_GATT_OK)? BTA_HH_OK : BTA_HH_ERR;
+    p_dev_cb->w4_evt = 0;
+    (* bta_hh_cb.p_cback)(cb_evt, (tBTA_HH *)&cback_data);
+
+
+}
+#endif
+
+
+
+
diff --git a/bta/hh/bta_hh_main.c b/bta/hh/bta_hh_main.c
index 1c03469..377f3a5 100644
--- a/bta/hh/bta_hh_main.c
+++ b/bta/hh/bta_hh_main.c
@@ -51,6 +51,23 @@
     BTA_HH_GET_DSCP_ACT,
     BTA_HH_MAINT_DEV_ACT,
     BTA_HH_OPEN_CMPL_ACT,
+    BTA_HH_OPEN_FAILURE,
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    BTA_HH_GATT_CLOSE,
+    BTA_HH_LE_OPEN_FAIL,
+    BTA_HH_GATT_OPEN,
+    BTA_HH_W4_LE_READ_CHAR,
+    BTA_HH_LE_READ_CHAR,
+    BTA_HH_W4_LE_READ_DESCR,
+    BTA_HH_LE_READ_DESCR,
+    BTA_HH_W4_LE_WRITE,
+    BTA_HH_LE_WRITE,
+    BTA_HH_WRITE_DESCR,
+    BTA_HH_START_SEC,
+    BTA_HH_SEC_CMPL,
+    BTA_HH_LE_UPDATE_SCPP,
+
+#endif
     BTA_HH_NUM_ACTIONS
 };
 
@@ -73,7 +90,23 @@
     bta_hh_write_dev_act,
     bta_hh_get_dscp_act,
     bta_hh_maint_dev_act,
-    bta_hh_open_cmpl_act
+    bta_hh_open_cmpl_act,
+    bta_hh_open_failure
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    ,bta_hh_gatt_close
+    ,bta_hh_le_open_fail
+    ,bta_hh_gatt_open
+    ,bta_hh_w4_le_read_char_cmpl
+    ,bta_hh_le_read_char_cmpl
+    ,bta_hh_w4_le_read_descr_cmpl
+    ,bta_hh_le_read_descr_cmpl
+    ,bta_hh_w4_le_write_cmpl
+    ,bta_hh_le_write_cmpl
+    ,bta_hh_le_write_char_descr_cmpl
+    ,bta_hh_start_security
+    ,bta_hh_security_cmpl
+    ,bta_hh_le_update_scpp
+#endif
 };
 
 /* state table information */
@@ -97,6 +130,18 @@
 /* BTA_HH_API_GET_DSCP_EVT  */    {BTA_HH_IGNORE,        BTA_HH_IDLE_ST    },
 /* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST    },
 /* BTA_HH_OPEN_CMPL_EVT        */  {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST    }
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* BTA_HH_GATT_CLOSE_EVT    */   ,{BTA_HH_IGNORE,         BTA_HH_IDLE_ST    }
+/* BTA_HH_GATT_OPEN_EVT    */    ,{BTA_HH_GATT_OPEN,      BTA_HH_W4_CONN_ST }
+/* BTA_HH_START_ENC_EVT    */    ,{BTA_HH_IGNORE,         BTA_HH_IDLE_ST    }
+/* BTA_HH_ENC_CMPL_EVT     */    ,{BTA_HH_IGNORE,         BTA_HH_IDLE_ST    }
+/* READ_CHAR_CMPL_EVT */         ,{BTA_HH_IGNORE,       BTA_HH_IDLE_ST  }
+/* BTA_HH_GATT_WRITE_CMPL_EVT*/    ,{BTA_HH_IGNORE,       BTA_HH_IDLE_ST  }
+/* READ_DESCR_CMPL_EVT */        ,{BTA_HH_IGNORE,           BTA_HH_IDLE_ST  }
+/* WRITE_DESCR_CMPL_EVT */       ,{BTA_HH_IGNORE,           BTA_HH_IDLE_ST   }
+/* SCPP_UPDATE_EVT */            ,{BTA_HH_IGNORE,           BTA_HH_IDLE_ST   }
+#endif
+
 };
 
 
@@ -106,15 +151,26 @@
 /* BTA_HH_API_OPEN_EVT      */    {BTA_HH_IGNORE,        BTA_HH_W4_CONN_ST },
 /* BTA_HH_API_CLOSE_EVT     */    {BTA_HH_IGNORE,        BTA_HH_IDLE_ST    },
 /* BTA_HH_INT_OPEN_EVT      */    {BTA_HH_OPEN_ACT,      BTA_HH_W4_CONN_ST },
-/* BTA_HH_INT_CLOSE_EVT     */    {BTA_HH_CLOSE_ACT,     BTA_HH_IDLE_ST    },
+/* BTA_HH_INT_CLOSE_EVT     */    {BTA_HH_OPEN_FAILURE,  BTA_HH_IDLE_ST    },
 /* BTA_HH_INT_DATA_EVT      */    {BTA_HH_IGNORE,        BTA_HH_W4_CONN_ST },
 /* BTA_HH_INT_CTRL_DATA     */    {BTA_HH_IGNORE,        BTA_HH_W4_CONN_ST },
 /* BTA_HH_INT_HANDSK_EVT    */    {BTA_HH_IGNORE,        BTA_HH_W4_CONN_ST },
 /* BTA_HH_SDP_CMPL_EVT      */    {BTA_HH_SDP_CMPL,      BTA_HH_W4_CONN_ST },
-/* BTA_HH_API_WRITE_DEV_EVT */    {BTA_HH_IGNORE  ,      BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */    {BTA_HH_WRITE_DEV_ACT, BTA_HH_W4_CONN_ST },
 /* BTA_HH_API_GET_DSCP_EVT  */    {BTA_HH_IGNORE,        BTA_HH_W4_CONN_ST },
 /* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST    },
 /* BTA_HH_OPEN_CMPL_EVT     */    {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST    }
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* BTA_HH_GATT_CLOSE_EVT    */   ,{BTA_HH_LE_OPEN_FAIL,  BTA_HH_IDLE_ST    }
+/* BTA_HH_GATT_OPEN_EVT    */    ,{BTA_HH_GATT_OPEN,     BTA_HH_W4_CONN_ST }
+/* BTA_HH_START_ENC_EVT    */    ,{BTA_HH_START_SEC,     BTA_HH_W4_SEC     }
+/* BTA_HH_ENC_CMPL_EVT     */    ,{BTA_HH_IGNORE,        BTA_HH_W4_CONN_ST }
+/* READ_CHAR_CMPL_EVT */        ,{BTA_HH_W4_LE_READ_CHAR,    BTA_HH_W4_CONN_ST  }
+/* BTA_HH_GATT_WRITE_CMPL_EVT*/  ,{BTA_HH_W4_LE_WRITE,    BTA_HH_W4_CONN_ST  }
+/* READ_DESCR_CMPL_EVT */        ,{BTA_HH_W4_LE_READ_DESCR, BTA_HH_W4_CONN_ST  }
+/* WRITE_DESCR_CMPL_EVT */       ,{BTA_HH_WRITE_DESCR,   BTA_HH_W4_CONN_ST   }
+/* SCPP_UPDATE_EVT */            ,{BTA_HH_IGNORE,           BTA_HH_W4_CONN_ST   }
+#endif
 };
 
 
@@ -133,7 +189,45 @@
 /* BTA_HH_API_GET_DSCP_EVT  */    {BTA_HH_GET_DSCP_ACT,  BTA_HH_CONN_ST    },
 /* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST    },
 /* BTA_HH_OPEN_CMPL_EVT        */    {BTA_HH_IGNORE,         BTA_HH_CONN_ST    }
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* BTA_HH_GATT_CLOSE_EVT    */    ,{BTA_HH_GATT_CLOSE,    BTA_HH_IDLE_ST    }
+/* BTA_HH_GATT_OPEN_EVT    */    ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST    }
+/* BTA_HH_START_ENC_EVT    */    ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST     }
+/* BTA_HH_ENC_CMPL_EVT     */    ,{BTA_HH_IGNORE,        BTA_HH_CONN_ST     }
+/* READ_CHAR_CMPL_EVT */         ,{BTA_HH_LE_READ_CHAR,  BTA_HH_CONN_ST     }
+/* WRITE_CHAR_CMPL_EVT*/         ,{BTA_HH_LE_WRITE,      BTA_HH_CONN_ST     }
+/* READ_DESCR_CMPL_EVT */        ,{BTA_HH_LE_READ_DESCR, BTA_HH_CONN_ST     }   /* do not currently read any descr when connection up */
+/* WRITE_DESCR_CMPL_EVT */       ,{BTA_HH_WRITE_DESCR,   BTA_HH_CONN_ST     }   /* do not currently write any descr when connection up */
+/* SCPP_UPDATE_EVT */            ,{BTA_HH_LE_UPDATE_SCPP,  BTA_HH_CONN_ST   }
+#endif
 };
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+const UINT8 bta_hh_st_w4_sec[][BTA_HH_NUM_COLS] =
+{
+/* Event                          Action                 Next state */
+/* BTA_HH_API_OPEN_EVT      */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_API_CLOSE_EVT     */    {BTA_HH_API_DISC_ACT,  BTA_HH_W4_SEC  },
+/* BTA_HH_INT_OPEN_EVT      */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_INT_CLOSE_EVT     */    {BTA_HH_OPEN_FAILURE,  BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT      */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_INT_CTRL_DATA     */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_INT_HANDSK_EVT    */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_SDP_CMPL_EVT      */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_API_WRITE_DEV_EVT */    {BTA_HH_IGNORE  ,      BTA_HH_W4_SEC  },
+/* BTA_HH_API_GET_DSCP_EVT  */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_API_MAINT_DEV_EVT */    {BTA_HH_MAINT_DEV_ACT, BTA_HH_W4_SEC  },
+/* BTA_HH_OPEN_CMPL_EVT     */    {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_GATT_CLOSE_EVT    */    {BTA_HH_LE_OPEN_FAIL,  BTA_HH_IDLE_ST },
+/* BTA_HH_GATT_OPEN_EVT    */     {BTA_HH_IGNORE,        BTA_HH_W4_SEC  },
+/* BTA_HH_START_ENC_EVT    */     {BTA_HH_IGNORE,        BTA_HH_W4_SEC     },
+/* BTA_HH_ENC_CMPL_EVT     */     {BTA_HH_SEC_CMPL,      BTA_HH_W4_CONN_ST },
+/* READ_CHAR_CMPL_EVT */          {BTA_HH_IGNORE,        BTA_HH_W4_SEC     },
+/* BTA_HH_GATT_WRITE_CMPL_EVT*/   {BTA_HH_IGNORE,        BTA_HH_W4_SEC     },
+/* READ_DESCR_CMPL_EVT */         {BTA_HH_IGNORE,        BTA_HH_W4_SEC   },
+/* WRITE_DESCR_CMPL_EVT */        {BTA_HH_IGNORE,        BTA_HH_W4_SEC   }
+/* SCPP_UPDATE_EVT */            ,{BTA_HH_IGNORE,        BTA_HH_W4_SEC   }
+};
+#endif
 
 /* type for state table */
 typedef const UINT8 (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS];
@@ -144,6 +238,9 @@
     bta_hh_st_idle,
     bta_hh_st_w4_conn,
     bta_hh_st_connected
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    ,bta_hh_st_w4_sec
+#endif
 };
 
 /*****************************************************************************
@@ -218,6 +315,10 @@
             case BTA_HH_API_WRITE_DEV_EVT:
                 cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                         BTA_HH_FST_TRANS_CB_EVT;
+                if (p_data->api_sndcmd.p_data != NULL)
+                {
+                    GKI_freebuf(p_data->api_sndcmd.p_data);
+                }
                 if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
                     p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
                     p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
@@ -268,6 +369,12 @@
                           bta_hh_evt_code(debug_event));
 #endif
 
+        if (in_state >= BTA_HH_INVALID_ST)
+        {
+            APPL_TRACE_ERROR2("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
+                              in_state,event);
+            return;
+        }
         state_table = bta_hh_st_tbl[p_cb->state - 1];
 
         event &= 0xff;
@@ -351,6 +458,10 @@
 // btla-specific --
                 }
             }
+            else if (p_msg->event == BTA_HH_INT_OPEN_EVT)
+            {
+                index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
+            }
             else
                 index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
 
@@ -412,6 +523,24 @@
         return "BTA_HH_API_GET_DSCP_EVT";
     case BTA_HH_OPEN_CMPL_EVT:
         return "BTA_HH_OPEN_CMPL_EVT";
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    case BTA_HH_GATT_CLOSE_EVT:
+        return "BTA_HH_GATT_CLOSE_EVT";
+    case BTA_HH_GATT_OPEN_EVT:
+        return "BTA_HH_GATT_OPEN_EVT";
+    case BTA_HH_START_ENC_EVT:
+        return "BTA_HH_START_ENC_EVT";
+    case BTA_HH_ENC_CMPL_EVT:
+        return "BTA_HH_ENC_CMPL_EVT";
+    case BTA_HH_GATT_READ_CHAR_CMPL_EVT:
+        return "BTA_HH_GATT_READ_CHAR_CMPL_EVT";
+    case BTA_HH_GATT_WRITE_CHAR_CMPL_EVT:
+        return "BTA_HH_GATT_WRITE_CHAR_CMPL_EVT";
+    case BTA_HH_GATT_READ_DESCR_CMPL_EVT:
+        return "BTA_HH_GATT_READ_DESCR_CMPL_EVT";
+    case BTA_HH_GATT_WRITE_DESCR_CMPL_EVT:
+        return "BTA_HH_GATT_WRITE_DESCR_CMPL_EVT";
+#endif
     default:
         return "unknown HID Host event code";
     }
@@ -438,6 +567,10 @@
         return "BTA_HH_W4_CONN_ST";
     case BTA_HH_CONN_ST:
         return "BTA_HH_CONN_ST";
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    case BTA_HH_W4_SEC:
+        return "BTA_HH_W4_SEC";
+#endif
     default:
         return "unknown HID Host state";
     }
diff --git a/bta/hh/bta_hh_utils.c b/bta/hh/bta_hh_utils.c
index bea0f2b..0c67513 100644
--- a/bta/hh/bta_hh_utils.c
+++ b/bta/hh/bta_hh_utils.c
@@ -123,6 +123,11 @@
 
     if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE )
     {
+#if BTA_HH_LE_INCLUDED == TRUE
+        if (p_cb->is_le_device)
+            bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = BTA_HH_IDX_INVALID;
+        else
+#endif
             bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID;
     }
 
@@ -158,6 +163,9 @@
     p_cb->dscp_info.vendor_id     =   vendor_id;
     p_cb->dscp_info.product_id    =   product_id;
     p_cb->dscp_info.version       =   version;
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    p_cb->dscp_info.flag          =   flag;
+#endif
 }
 /*******************************************************************************
 **
@@ -483,6 +491,17 @@
 {
     UINT8 index = BTA_HH_IDX_INVALID;
 
+#if BTA_HH_LE_INCLUDED == TRUE
+    if (BTA_HH_IS_LE_DEV_HDL(dev_handle))
+    {
+        if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle))
+            index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)];
+#if BTA_HH_DEBUG == TRUE
+        APPL_TRACE_DEBUG2("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d", dev_handle, index);
+#endif
+    }
+    else
+#endif
         /* regular HID device checking */
         if (dev_handle < BTA_HH_MAX_KNOWN )
         index = bta_hh_cb.cb_index[dev_handle];
diff --git a/bta/include/bta_hh_api.h b/bta/include/bta_hh_api.h
index 2cd29f4..893cac5 100644
--- a/bta/include/bta_hh_api.h
+++ b/bta/include/bta_hh_api.h
@@ -21,11 +21,15 @@
 #include "bta_api.h"
 #include "hidh_api.h"
 
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#endif
+
 /*****************************************************************************
 **  Constants and Type Definitions
 *****************************************************************************/
 #ifndef BTA_HH_DEBUG
-#define BTA_HH_DEBUG    FALSE
+#define BTA_HH_DEBUG    TRUE
 #endif
 
 #ifndef BTA_HH_SSR_MAX_LATENCY_DEF
@@ -47,12 +51,13 @@
 #define BTA_HH_SET_PROTO_EVT    7       /* BTA_HhSetProtoMode callback */
 #define BTA_HH_GET_IDLE_EVT     8       /* BTA_HhGetIdle comes callback */
 #define BTA_HH_SET_IDLE_EVT     9       /* BTA_HhSetIdle finish callback */
-#define BTA_HH_GET_DSCP_EVT     10      /* Get report descripotor */
+#define BTA_HH_GET_DSCP_EVT     10      /* Get report descriptor */
 #define BTA_HH_ADD_DEV_EVT      11      /* Add Device callback */
 #define BTA_HH_RMV_DEV_EVT      12      /* remove device finished */
 #define BTA_HH_VC_UNPLUG_EVT    13      /* virtually unplugged */
 #define BTA_HH_DATA_EVT         15
 #define BTA_HH_API_ERR_EVT      16      /* API error is caught */
+#define BTA_HH_UPDATE_SCPP_EVT  17       /* update scan paramter complete */
 
 typedef UINT16 tBTA_HH_EVT;
 
@@ -71,8 +76,14 @@
 /* HID_HOST_MAX_DEVICES can not exceed 15 for th design of BTA HH */
 #define BTA_HH_IDX_INVALID      0xff
 #define BTA_HH_MAX_KNOWN        HID_HOST_MAX_DEVICES
-#define BTA_HH_MAX_DEVICE       HID_HOST_MAX_DEVICES
 
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+/* GATT_MAX_PHY_CHANNEL can not exceed 14 for the design of BTA HH */
+#define BTA_HH_LE_MAX_KNOWN     GATT_MAX_PHY_CHANNEL
+#define BTA_HH_MAX_DEVICE        (HID_HOST_MAX_DEVICES + GATT_MAX_PHY_CHANNEL)
+#else
+#define BTA_HH_MAX_DEVICE       HID_HOST_MAX_DEVICES
+#endif
 /* invalid device handle */
 #define BTA_HH_INVALID_HANDLE   0xff
 
@@ -115,6 +126,7 @@
     BTA_HH_ERR_SDP,             /* SDP error */
     BTA_HH_ERR_PROTO,           /* SET_Protocol error,
                                     only used in BTA_HH_OPEN_EVT callback */
+
     BTA_HH_ERR_DB_FULL,         /* device database full error, used in
                                    BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */
     BTA_HH_ERR_TOD_UNSPT,       /* type of device not supported */
@@ -136,7 +148,6 @@
 #define BTA_HH_SEC_REQUIRED             HID_SEC_REQUIRED
 typedef UINT16 tBTA_HH_ATTR_MASK;
 
-
 /* supported type of device and corresponding application ID */
 typedef struct
 {
@@ -191,6 +202,12 @@
     UINT16              ssr_max_latency;    /* SSR max latency, BTA_HH_SSR_PARAM_INVALID if unknown */
     UINT16              ssr_min_tout;       /* SSR min timeout, BTA_HH_SSR_PARAM_INVALID if unknown */
     UINT8               ctry_code;      /*Country Code.*/
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_REMOTE_WAKE       0x01
+#define BTA_HH_LE_NORMAL_CONN       0x02
+
+    UINT8               flag;
+#endif
     tBTA_HH_DEV_DESCR   descriptor;
 }tBTA_HH_DEV_DSCP_INFO;
 
@@ -200,6 +217,11 @@
     BD_ADDR         bda;                /* HID device bd address    */
     tBTA_HH_STATUS  status;             /* operation status         */
     UINT8           handle;             /* device handle            */
+#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
+    BOOLEAN         le_hid;             /* is LE devices? */
+    BOOLEAN         scps_supported;     /* scan parameter service supported */
+#endif
+
 } tBTA_HH_CONN;
 
 typedef tBTA_HH_CONN tBTA_HH_DEV_INFO;
@@ -275,7 +297,8 @@
     tBTA_HH_CBDATA          dev_status;         /* BTA_HH_CLOSE_EVT,
                                                    BTA_HH_SET_PROTO_EVT
                                                    BTA_HH_SET_RPT_EVT
-                                                   BTA_HH_SET_IDLE_EVT  */
+                                                   BTA_HH_SET_IDLE_EVT
+                                                   BTA_HH_UPDATE_SCPP_EVT */
 
     tBTA_HH_STATUS          status;             /* BTA_HH_ENABLE_EVT */
     tBTA_HH_DEV_DSCP_INFO   dscp_info;          /* BTA_HH_GET_DSCP_EVT */
@@ -469,7 +492,6 @@
 BTA_API extern void BTA_HhGetDscpInfo(UINT8 dev_handle);
 
 /*******************************************************************************
-**
 ** Function         BTA_HhAddDev
 **
 ** Description      Add a virtually cabled device into HID-Host device list
@@ -511,6 +533,19 @@
 BTA_API extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report,
                                        UINT16 report_len);
 
+#if BTA_HH_LE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function         BTA_HhUpdateLeScanParam
+**
+** Description      Update the scan paramteters if connected to a LE hid device as
+**                  report host.
+**
+** Returns          void
+**
+*******************************************************************************/
+BTA_API extern void BTA_HhUpdateLeScanParam(UINT8 dev_handle, UINT16 scan_int, UINT16 scan_win);
+#endif
 /* test commands */
 BTA_API extern void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id);
 
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
index 21512b5..0a71eec 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -139,6 +139,7 @@
 extern bt_status_t btif_av_execute_service(BOOLEAN b_enable);
 extern bt_status_t btif_hh_execute_service(BOOLEAN b_enable);
 extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
+extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16);
 
 
 /******************************************************************************
@@ -285,7 +286,28 @@
         if ((remote_cod & 0x700) == cod)
             return TRUE;
     }
+    return FALSE;
+}
 
+BOOLEAN check_hid_le(const bt_bdaddr_t *remote_bdaddr)
+{
+    uint32_t    remote_dev_type;
+    bt_property_t prop_name;
+
+    /* check if we already have it in our btif_storage cache */
+    BTIF_STORAGE_FILL_PROPERTY(&prop_name,BT_PROPERTY_TYPE_OF_DEVICE,
+                               sizeof(uint32_t), &remote_dev_type);
+    if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr,
+                                &prop_name) == BT_STATUS_SUCCESS)
+    {
+        if (remote_dev_type == BT_DEVICE_DEVTYPE_BLE)
+        {
+            bdstr_t bdstr;
+            bd2str(remote_bdaddr, &bdstr);
+            if(btif_config_exist("Remote", bdstr, "HidAppId"))
+                return TRUE;
+        }
+    }
     return FALSE;
 }
 
@@ -1106,12 +1128,15 @@
                  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
             }
 
-            /* Also write this to the NVRAM */
-            ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
-            ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
-            /* Send the event to the BTIF */
-            HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
-                             BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+            if(p_data->disc_res.num_uuids != 0)
+            {
+                /* Also write this to the NVRAM */
+                ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+                ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+                /* Send the event to the BTIF */
+                HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+                                 BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+            }
         }
         break;
 
@@ -1119,6 +1144,45 @@
             /* fixme */
         break;
 
+        case BTA_DM_DISC_BLE_RES_EVT:
+             BTIF_TRACE_DEBUG2("%s:, services 0x%x)", __FUNCTION__,
+                                p_data->disc_ble_res.service.uu.uuid16);
+             bt_uuid_t  uuid;
+             int i = 0;
+             int j = 15;
+             if (p_data->disc_ble_res.service.uu.uuid16 == UUID_SERVCLASS_LE_HID)
+             {
+                BTIF_TRACE_DEBUG1("%s: Found HOGP UUID",__FUNCTION__);
+                bt_property_t prop;
+                bt_bdaddr_t bd_addr;
+                char temp[256];
+
+                bta_gatt_convert_uuid16_to_uuid128(uuid.uu,p_data->disc_ble_res.service.uu.uuid16);
+
+                while(i < j )
+                {
+                    unsigned char c = uuid.uu[j];
+                    uuid.uu[j] = uuid.uu[i];
+                    uuid.uu[i] = c;
+                    i++;
+                    j--;
+                }
+
+                uuid_to_string(&uuid, temp);
+                BTIF_TRACE_ERROR1(" uuid:%s", temp);
+
+                bdcpy(bd_addr.address, p_data->disc_ble_res.bd_addr);
+                prop.type = BT_PROPERTY_UUIDS;
+                prop.val = uuid.uu;
+                prop.len = MAX_UUID_SIZE;
+
+                /* Send the event to the BTIF */
+                HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+                                 BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+
+            }
+        break;
+
         default:
         {
             ASSERTC(0, "unhandled search services event", event);
@@ -1294,6 +1358,9 @@
             #if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
             btif_hh_remove_device(bd_addr);
             #endif
+            #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
+            btif_storage_remove_ble_bonding_keys(&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/gki/ulinux/data_types.h b/gki/ulinux/data_types.h
index 8cd086a..33b8bb7 100644
--- a/gki/ulinux/data_types.h
+++ b/gki/ulinux/data_types.h
@@ -30,6 +30,8 @@
 typedef unsigned char   UINT8;
 typedef unsigned short  UINT16;
 typedef unsigned long   UINT32;
+typedef unsigned long long      UINT64;
+
 typedef signed   long   INT32;
 typedef signed   char   INT8;
 typedef signed   short  INT16;
diff --git a/include/bt_target.h b/include/bt_target.h
index 0ce6971..4484ac7 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -187,6 +187,10 @@
 #define BTA_HH_ROLE BTA_MASTER_ROLE_PREF
 #endif
 
+#ifndef BTA_HH_LE_INCLUDED
+#define BTA_HH_LE_INCLUDED TRUE
+#endif
+
 #ifndef BTA_AR_INCLUDED
 #define BTA_AR_INCLUDED TRUE
 #endif
diff --git a/stack/Android.mk b/stack/Android.mk
index f677ad2..10e9bef 100755
--- a/stack/Android.mk
+++ b/stack/Android.mk
@@ -18,6 +18,7 @@
                    $(LOCAL_PATH)/hid \
                    $(LOCAL_PATH)/sdp \
                    $(LOCAL_PATH)/smp \
+                   $(LOCAL_PATH)/srvc \
                    $(LOCAL_PATH)/../include \
                    $(LOCAL_PATH)/../gki/common \
                    $(LOCAL_PATH)/../gki/ulinux \
@@ -83,10 +84,6 @@
     ./mcap/mca_csm.c \
     ./mcap/mca_cact.c \
     ./mcap/mca_api.c \
-     ./gap/gap_ble.c \
-    ./gap/gap_api.c \
-    ./gap/gap_utils.c \
-    ./gap/gap_conn.c \
     ./gatt/gatt_sr.c \
     ./gatt/gatt_cl.c \
     ./gatt/gatt_api.c \
@@ -103,12 +100,12 @@
     ./avct/avct_lcb_act.c \
     ./smp/smp_main.c \
     ./smp/smp_l2c.c \
-    ./smp/aes.c \
     ./smp/smp_cmac.c \
     ./smp/smp_utils.c \
     ./smp/smp_act.c \
     ./smp/smp_keys.c \
     ./smp/smp_api.c \
+    ./smp/aes.c \
     ./avdt/avdt_ccb.c \
     ./avdt/avdt_scb_act.c \
     ./avdt/avdt_msg.c \
@@ -124,6 +121,12 @@
     ./sdp/sdp_api.c \
     ./sdp/sdp_discovery.c \
     ./pan/pan_main.c \
+    ./srvc/srvc_battery.c \
+    ./srvc/srvc_battery_int.h \
+    ./srvc/srvc_dis.c \
+    ./srvc/srvc_dis_int.h \
+    ./srvc/srvc_eng.c \
+    ./srvc/srvc_eng_int.h \
     ./pan/pan_api.c \
     ./pan/pan_utils.c \
     ./btu/btu_hcif.c \
@@ -136,7 +139,11 @@
     ./l2cap/l2c_utils.c \
     ./l2cap/l2c_csm.c \
     ./l2cap/l2c_link.c \
-    ./l2cap/l2c_ble.c
+    ./l2cap/l2c_ble.c \
+    ./gap/gap_api.c \
+    ./gap/gap_ble.c \
+    ./gap/gap_conn.c \
+    ./gap/gap_utils.c
 
 LOCAL_MODULE := libbt-brcm_stack
 LOCAL_MODULE_TAGS := optional
diff --git a/stack/hid/hidh_api.c b/stack/hid/hidh_api.c
index 4f048fc..1868671 100644
--- a/stack/hid/hidh_api.c
+++ b/stack/hid/hidh_api.c
@@ -33,6 +33,7 @@
 #include "hidh_int.h"
 #include "btm_api.h"
 #include "btu.h"
+#include "btm_int.h"
 
 #if HID_DYNAMIC_MEMORY == FALSE
 tHID_HOST_CTB   hh_cb;
@@ -336,7 +337,6 @@
 {
     int i;
     /* Find an entry for this device in hh_cb.devices array */
-
     if( !hh_cb.reg_flag )
         return (HID_ERR_NOT_REGISTERED);
 
@@ -367,7 +367,8 @@
         hh_cb.devices[i].conn_tries = 0 ;
     }
 
-    hh_cb.devices[i].attr_mask = attr_mask;
+    if (attr_mask != HID_ATTR_MASK_IGNORE)
+        hh_cb.devices[i].attr_mask = attr_mask;
 
     *handle = i;
 
@@ -500,42 +501,42 @@
 
 tHID_STATUS HID_HostSetSecurityLevel( char serv_name[], UINT8 sec_lvl )
 {
-    if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
+    if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
                                sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
     {
         HIDH_TRACE_ERROR0 ("Security Registration 1 failed");
         return (HID_ERR_NO_RESOURCES);
     }
 
-    if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_SEC_CTRL,
+    if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
                                sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
     {
         HIDH_TRACE_ERROR0 ("Security Registration 2 failed");
         return (HID_ERR_NO_RESOURCES);
     }
 
-    if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
+    if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
                                BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
     {
         HIDH_TRACE_ERROR0 ("Security Registration 3 failed");
         return (HID_ERR_NO_RESOURCES);
     }
 
-    if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_NOSEC_CTRL,
+    if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
                                BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
     {
         HIDH_TRACE_ERROR0 ("Security Registration 4 failed");
         return (HID_ERR_NO_RESOURCES);
     }
 
-    if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HID_INTR,
+    if (!BTM_SetSecurityLevel (TRUE, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
                                BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
     {
         HIDH_TRACE_ERROR0 ("Security Registration 5 failed");
         return (HID_ERR_NO_RESOURCES);
     }
 
-    if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HID_INTR,
+    if (!BTM_SetSecurityLevel (FALSE, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
                                BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
     {
         HIDH_TRACE_ERROR0 ("Security Registration 6 failed");
@@ -544,3 +545,55 @@
 
     return( HID_SUCCESS );
 }
+
+/******************************************************************************
+**
+** Function         hid_known_hid_device
+**
+** Description      check if this device is  of type HID Device
+**
+** Returns          TRUE if device is HID Device else FALSE
+**
+*******************************************************************************/
+BOOLEAN hid_known_hid_device (BD_ADDR bd_addr)
+{
+    UINT8 i;
+    tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(bd_addr);
+
+     if ( !hh_cb.reg_flag )
+        return FALSE;
+
+    /* First  check for class of device , if Inq DB has information about this device*/
+    if (p_inq_info != NULL)
+    {
+        /* Check if remote major device class is of type BTM_COD_MAJOR_PERIPHERAL */
+        if ((p_inq_info->results.dev_class[1] & BTM_COD_MAJOR_CLASS_MASK)
+            == BTM_COD_MAJOR_PERIPHERAL )
+        {
+            HIDH_TRACE_DEBUG0("hid_known_hid_device:dev found in InqDB & COD matches HID dev");
+            return TRUE;
+        }
+    }
+    else
+    {
+        /* Look for this device in security device DB */
+        tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+        if ((p_dev_rec != NULL) &&
+            ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL ))
+        {
+            HIDH_TRACE_DEBUG0("hid_known_hid_device:dev found in SecDevDB & COD matches HID dev");
+            return TRUE;
+        }
+    }
+
+    /* Find an entry for this device in hh_cb.devices array */
+     for ( i=0; i<HID_HOST_MAX_DEVICES; i++)
+     {
+         if ((hh_cb.devices[i].in_use) &&
+            (memcmp(bd_addr, hh_cb.devices[i].addr, BD_ADDR_LEN) == 0))
+             return TRUE;
+     }
+    /* Check if this device is marked as HID Device in IOP Dev */
+    HIDH_TRACE_DEBUG0("hid_known_hid_device:remote is not HID device");
+    return FALSE;
+}
diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c
index 2fe1f3d..d9345a0 100644
--- a/stack/hid/hidh_conn.c
+++ b/stack/hid/hidh_conn.c
@@ -129,7 +129,7 @@
 {
     tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
 
-    HIDH_TRACE_EVENT0 ("HID - disconnect");
+    HIDH_TRACE_EVENT0 ("HID-Host disconnect");
 
     if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
     {
@@ -201,18 +201,13 @@
 {
     tHID_CONN    *p_hcon;
     BOOLEAN      bAccept = TRUE;
-    int i;
+    UINT8        i = HID_HOST_MAX_DEVICES;
     tHID_HOST_DEV_CTB *p_dev;
 
-    HIDH_TRACE_EVENT2 ("HID - Rcvd L2CAP conn ind, PSM: 0x%04x  CID 0x%x", psm, l2cap_cid);
+    HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x  CID 0x%x", psm, l2cap_cid);
 
-    for( i=0; i < HID_HOST_MAX_DEVICES; i++ )
-    {
-        if( hh_cb.devices[i].in_use && (!memcmp(bd_addr, hh_cb.devices[i].addr, sizeof(BD_ADDR))) )
-            break;
-    }
-
-    if (i >= HID_HOST_MAX_DEVICES)
+    /* always add incoming connection device into HID database by default */
+    if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
     {
         L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
         return;
@@ -226,12 +221,13 @@
     {
         if (p_hcon->ctrl_cid == 0)
         {
-            HIDH_TRACE_WARNING0 ("HID - Rcvd INTR L2CAP conn ind, but no CTL channel");
+            HIDH_TRACE_WARNING0 ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
             bAccept = FALSE;
         }
         if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
         {
-            HIDH_TRACE_WARNING1 ("HID - Rcvd INTR L2CAP conn ind, wrong state: %d", p_hcon->conn_state);
+            HIDH_TRACE_WARNING1 ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
+                                 p_hcon->conn_state);
             bAccept = FALSE;
         }
     }
@@ -243,7 +239,8 @@
 #else
         if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
         {
-            HIDH_TRACE_WARNING1 ("HID - Rcvd CTL L2CAP conn ind, wrong state: %d", p_hcon->conn_state);
+            HIDH_TRACE_WARNING1 ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
+                                 p_hcon->conn_state);
             bAccept = FALSE;
         }
 #endif
@@ -284,7 +281,8 @@
     /* Send a Configuration Request. */
     L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
 
-    HIDH_TRACE_EVENT2 ("HID - Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x  CID 0x%x", psm, l2cap_cid);
+    HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x  CID 0x%x",
+                       psm, l2cap_cid);
 }
 
 /*******************************************************************************
@@ -300,7 +298,8 @@
 {
     hidh_conn_initiate( (UINT8) p_tle->param ) ;
     hh_cb.devices[p_tle->param].conn_tries++;
-    hh_cb.callback( (UINT8) p_tle->param, HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
+    hh_cb.callback( (UINT8) p_tle->param, hh_cb.devices[p_tle->param].addr,
+                    HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
 }
 
 /*******************************************************************************
@@ -325,16 +324,16 @@
     dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
     if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
     {
-        HIDH_TRACE_EVENT0 ("HID - Originator security pass.");
+        HIDH_TRACE_EVENT0 ("HID-Host Originator security pass.");
         p_dev->conn.disc_reason = HID_SUCCESS;  /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
 
         /* Check if L2CAP started the connection process for interrupt channel */
         if ((p_dev->conn.intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
         {
-            HIDH_TRACE_WARNING0 ("HID - INTR Originate failed");
+            HIDH_TRACE_WARNING0 ("HID-Host INTR Originate failed");
             reason = HID_L2CAP_REQ_FAIL ;
             hidh_conn_disconnect (dhandle);
-            hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+            hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
             return;
         }
         else
@@ -394,7 +393,7 @@
      || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
      || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)))
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
         return;
     }
 
@@ -418,7 +417,7 @@
 #endif
         {
             reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
-            hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+            hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
         }
         return;
     }
@@ -442,7 +441,7 @@
     /* Send a Configuration Request. */
     L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
 
-    HIDH_TRACE_EVENT1 ("HID - got CTRL conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
+    HIDH_TRACE_EVENT1 ("HID-Host got CTRL conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
     return;
 }
 
@@ -471,11 +470,11 @@
 
     if (p_hcon == NULL)
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
         return;
     }
 
-    HIDH_TRACE_EVENT1 ("HID - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+    HIDH_TRACE_EVENT1 ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
 
     /* Remember the remote MTU size */
     if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
@@ -502,7 +501,7 @@
         p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
 
         hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
-        hh_cb.callback( dhandle, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+        hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
     }
 }
 
@@ -523,7 +522,7 @@
     tHID_CONN    *p_hcon = NULL;
     UINT32  reason;
 
-    HIDH_TRACE_EVENT2 ("HID - Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
+    HIDH_TRACE_EVENT2 ("HID-Host Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
 
     /* Find CCB based on CID */
     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
@@ -531,7 +530,7 @@
 
     if (p_hcon == NULL)
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
         return;
     }
 
@@ -540,7 +539,7 @@
     {
         hidh_conn_disconnect (dhandle);
         reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
-        hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+        hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
         return;
     }
 
@@ -556,7 +555,7 @@
         p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
 
         hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
-        hh_cb.callback( dhandle, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+        hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
     }
 }
 
@@ -584,14 +583,14 @@
 
     if (p_hcon == NULL)
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
         return;
     }
 
     if (ack_needed)
         L2CA_DisconnectRsp (l2cap_cid);
 
-    HIDH_TRACE_EVENT1 ("HID - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+    HIDH_TRACE_EVENT1 ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
 
     p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
 
@@ -636,7 +635,7 @@
                 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
             }
 
-            hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
+            hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
         }
     }
 }
@@ -662,11 +661,11 @@
 
     if (p_hcon == NULL)
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
         return;
     }
 
-    HIDH_TRACE_EVENT1 ("HID - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+    HIDH_TRACE_EVENT1 ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
 
     if (l2cap_cid == p_hcon->ctrl_cid)
         p_hcon->ctrl_cid = 0;
@@ -677,7 +676,7 @@
     {
         hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
-        hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
+        hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
     }
 }
 
@@ -702,11 +701,11 @@
 
     if (p_hcon == NULL)
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
         return;
     }
 
-    HIDH_TRACE_EVENT2 ("HID - Rcvd L2CAP congestion status, CID: 0x%x  Cong: %d", l2cap_cid, congested);
+    HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x  Cong: %d", l2cap_cid, congested);
 
     if (congested)
         p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
@@ -740,7 +739,7 @@
     UINT8 dhandle;
     tHID_CONN    *p_hcon = NULL;
 
-    HIDH_TRACE_DEBUG1 ("HID - hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
+    HIDH_TRACE_DEBUG1 ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
 
     /* Find CCB based on CID */
      if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
@@ -748,7 +747,7 @@
 
     if (p_hcon == NULL)
     {
-        HIDH_TRACE_WARNING1 ("HID - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+        HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
         GKI_freebuf (p_msg);
         return;
     }
@@ -766,7 +765,7 @@
     switch (ttype)
     {
     case HID_TRANS_HANDSHAKE:
-        hh_cb.callback(dhandle, HID_HDEV_EVT_HANDSHAKE, param, NULL);
+        hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
         GKI_freebuf (p_msg);
         break;
 
@@ -776,7 +775,7 @@
         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
             hidh_conn_disconnect( dhandle ) ;
             /* Device is unplugging from us. Tell USB */
-            hh_cb.callback(dhandle, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
+            hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
             break;
 
         default:
@@ -789,13 +788,13 @@
     case HID_TRANS_DATA:
         evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
                     HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
-        hh_cb.callback(dhandle, evt, rep_type, p_msg);
+        hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
         break;
 
     case HID_TRANS_DATAC:
         evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
                     HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
-        hh_cb.callback(dhandle, evt, rep_type, p_msg);
+        hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
         break;
 
     default:
@@ -949,7 +948,7 @@
 *******************************************************************************/
 tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
 {
-    UINT8   service_id = BTM_SEC_SERVICE_HID_NOSEC_CTRL;
+    UINT8   service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
     UINT32  mx_chan_id = HID_NOSEC_CHN;
 
     tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
@@ -966,7 +965,7 @@
 
     if(p_dev->attr_mask & HID_SEC_REQUIRED)
     {
-        service_id = BTM_SEC_SERVICE_HID_SEC_CTRL;
+        service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
         mx_chan_id = HID_SEC_CHN;
     }
     BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
@@ -974,8 +973,9 @@
     /* Check if L2CAP started the connection process */
     if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
     {
-        HIDH_TRACE_WARNING0 ("HID - Originate failed");
-        hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL ) ;
+        HIDH_TRACE_WARNING0 ("HID-Host Originate failed");
+        hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+                                HID_ERR_L2CAP_FAILED, NULL ) ;
     }
     else
     {
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 3a7ed1d..2181f31 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -1185,9 +1185,9 @@
 #define BTM_SEC_SERVICE_TE_PHONE_ACCESS 30
 #define BTM_SEC_SERVICE_ME_PHONE_ACCESS 31
 
-#define BTM_SEC_SERVICE_HID_SEC_CTRL    32
-#define BTM_SEC_SERVICE_HID_NOSEC_CTRL  33
-#define BTM_SEC_SERVICE_HID_INTR        34
+#define BTM_SEC_SERVICE_HIDH_SEC_CTRL   32
+#define BTM_SEC_SERVICE_HIDH_NOSEC_CTRL 33
+#define BTM_SEC_SERVICE_HIDH_INTR       34
 #define BTM_SEC_SERVICE_BIP             35
 #define BTM_SEC_SERVICE_BIP_REF         36
 #define BTM_SEC_SERVICE_AVDTP           37
@@ -1272,9 +1272,9 @@
 #define BTM_SEC_TRUST_ME_PHONE_ACCESS   (1 << BTM_SEC_SERVICE_ME_PHONE_ACCESS)
 
 /* 0..31 bits of mask[1] (Most Significant Word) */
-#define BTM_SEC_TRUST_HID_CTRL          (1 << (BTM_SEC_SERVICE_HID_SEC_CTRL - 32))
-#define BTM_SEC_TRUST_HID_NOSEC_CTRL    (1 << (BTM_SEC_SERVICE_HID_NOSEC_CTRL - 32))
-#define BTM_SEC_TRUST_HID_INTR          (1 << (BTM_SEC_SERVICE_HID_INTR - 32))
+#define BTM_SEC_TRUST_HIDH_CTRL         (1 << (BTM_SEC_SERVICE_HIDH_SEC_CTRL - 32))
+#define BTM_SEC_TRUST_HIDH_NOSEC_CTRL   (1 << (BTM_SEC_SERVICE_HIDH_NOSEC_CTRL - 32))
+#define BTM_SEC_TRUST_HIDH_INTR         (1 << (BTM_SEC_SERVICE_HIDH_INTR - 32))
 #define BTM_SEC_TRUST_BIP               (1 << (BTM_SEC_SERVICE_BIP - 32))
 #define BTM_SEC_TRUST_BIP_REF           (1 << (BTM_SEC_SERVICE_BIP_REF - 32))
 #define BTM_SEC_TRUST_AVDTP             (1 << (BTM_SEC_SERVICE_AVDTP - 32))
diff --git a/stack/include/gattdefs.h b/stack/include/gattdefs.h
index e2150f2..38e18f3 100644
--- a/stack/include/gattdefs.h
+++ b/stack/include/gattdefs.h
@@ -57,4 +57,69 @@
 #define GATT_UUID_GATT_SRV_CHGD         0x2A05
 /* Attribute Protocol Test */
 
+/* Link Loss Service */
+#define GATT_UUID_ALERT_LEVEL           0x2A06      /* Alert Level */
+#define GATT_UUID_TX_POWER_LEVEL        0x2A07      /* TX power level */
+
+/* Time Profile */
+/* Current Time Service */
+#define GATT_UUID_CURRENT_TIME          0x2A2B      /* Current Time */
+#define GATT_UUID_LOCAL_TIME_INFO       0x2A0F      /* Local time info */
+#define GATT_UUID_REF_TIME_INFO         0x2A14      /* reference time information */
+
+/* NwA Profile */
+#define GATT_UUID_NW_STATUS             0x2A18      /* network availability status */
+#define GATT_UUID_NW_TRIGGER            0x2A1A      /* Network availability trigger */
+
+/* phone alert */
+#define GATT_UUID_ALERT_STATUS          0x2A40    /* alert status */
+#define GATT_UUID_RINGER_CP             0x2A42    /* ringer control point */
+#define GATT_UUID_RINGER_SETTING        0x2A41    /* ringer setting */
+
+/* Glucose Service */
+#define GATT_UUID_GM_MEASUREMENT        0x2A18
+#define GATT_UUID_GM_CONTEXT            0x2A34
+#define GATT_UUID_GM_CONTROL_POINT      0x2A52
+#define GATT_UUID_GM_FEATURE            0x2A51
+
+/* device infor characteristic */
+#define GATT_UUID_SYSTEM_ID             0x2A23
+#define GATT_UUID_MODEL_NUMBER_STR      0x2A24
+#define GATT_UUID_SERIAL_NUMBER_STR     0x2A25
+#define GATT_UUID_FW_VERSION_STR        0x2A26
+#define GATT_UUID_HW_VERSION_STR        0x2A27
+#define GATT_UUID_SW_VERSION_STR        0x2A28
+#define GATT_UUID_MANU_NAME             0x2A29
+#define GATT_UUID_IEEE_DATA             0x2A2A
+#define GATT_UUID_PNP_ID                0x2A50
+
+/* HID characteristics */
+#define GATT_UUID_HID_INFORMATION       0x2A4A
+#define GATT_UUID_HID_REPORT_MAP        0x2A4B
+#define GATT_UUID_HID_CONTROL_POINT     0x2A4C
+#define GATT_UUID_HID_REPORT            0x2A4D
+#define GATT_UUID_HID_PROTO_MODE        0x2A4E
+#define GATT_UUID_HID_BT_KB_INPUT       0x2A22
+#define GATT_UUID_HID_BT_KB_OUTPUT      0x2A32
+#define GATT_UUID_HID_BT_MOUSE_INPUT    0x2A33
+
+/* Battery Service char */
+#define GATT_UUID_BATTERY_LEVEL         0x2A19
+
+#define GATT_UUID_SC_CONTROL_POINT      0x2A55
+#define GATT_UUID_SENSOR_LOCATION       0x2A5D
+
+/* RUNNERS SPEED AND CADENCE SERVICE      */
+#define GATT_UUID_RSC_MEASUREMENT       0x2A53
+#define GATT_UUID_RSC_FEATURE           0x2A54
+
+/* CYCLING SPEED AND CADENCE SERVICE      */
+#define GATT_UUID_CSC_MEASUREMENT       0x2A5B
+#define GATT_UUID_CSC_FEATURE           0x2A5C
+
+
+/* Scan Parameter charatceristics */
+#define GATT_UUID_SCAN_INT_WINDOW       0x2A4F
+#define GATT_UUID_SCAN_REFRESH          0x2A31
+
 #endif
diff --git a/stack/include/hiddefs.h b/stack/include/hiddefs.h
index e29a4c4..bf5d021 100644
--- a/stack/include/hiddefs.h
+++ b/stack/include/hiddefs.h
@@ -49,6 +49,7 @@
    HID_ERR_L2CAP_FAILED,
    HID_ERR_AUTH_FAILED,
    HID_ERR_SDP_BUSY,
+   HID_ERR_GATT,
 
    HID_ERR_INVALID = 0xFF
 };
diff --git a/stack/include/hidh_api.h b/stack/include/hidh_api.h
index 4662630..27e8ac5 100644
--- a/stack/include/hidh_api.h
+++ b/stack/include/hidh_api.h
@@ -42,6 +42,7 @@
 #define HID_SSR_MIN_TOUT         0x0100
 
 #define HID_SEC_REQUIRED         0x8000
+#define HID_ATTR_MASK_IGNORE     0
 
 
 /*****************************************************************************
@@ -76,6 +77,7 @@
     HID_HDEV_EVT_VC_UNPLUG
 };
 typedef void (tHID_HOST_DEV_CALLBACK) (UINT8 dev_handle,
+                                       BD_ADDR addr,
                                        UINT8 event, /* Event from HID-DEVICE. */
                                        UINT32 data, /* Integer data corresponding to the event.*/
                                        BT_HDR *p_buf ); /* Pointer data corresponding to the event. */
@@ -205,6 +207,18 @@
 
 /*******************************************************************************
 **
+** Function         hid_known_hid_device
+**
+** Description      This function checks if this device is  of type HID Device
+**
+** Returns          TRUE if device exists else FALSE
+**
+*******************************************************************************/
+BOOLEAN hid_known_hid_device (BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
 ** Function         HID_HostSetTraceLevel
 **
 ** Description      This function sets the trace level for HID Host. If called with
diff --git a/stack/include/srvc_api.h b/stack/include/srvc_api.h
new file mode 100644
index 0000000..b67a14f
--- /dev/null
+++ b/stack/include/srvc_api.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+**  Name:       srvc_api.h
+**  Function    this file contains the definitions for the DIS API
+**
+**
+**  Copyright (c) 1999-2011, Broadcom Corp., All Rights Reserved.
+**  Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+#ifndef SRVC_DIS_API_H
+#define SRVC_DIS_API_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "gattdefs.h"
+
+#define DIS_SUCCESS             GATT_SUCCESS
+#define DIS_ILLEGAL_PARAM       GATT_ILLEGAL_PARAMETER
+#define DIS_NO_RESOURCES        GATT_NO_RESOURCES
+typedef UINT8 tDIS_STATUS;
+
+
+/*****************************************************************************
+**  Data structure for DIS
+*****************************************************************************/
+
+#define DIS_ATTR_SYS_ID_BIT         0x0001
+#define DIS_ATTR_MODEL_NUM_BIT      0x0002
+#define DIS_ATTR_SERIAL_NUM_BIT     0x0004
+#define DIS_ATTR_FW_NUM_BIT         0x0008
+#define DIS_ATTR_HW_NUM_BIT         0x0010
+#define DIS_ATTR_SW_NUM_BIT         0x0020
+#define DIS_ATTR_MANU_NAME_BIT      0x0040
+#define DIS_ATTR_IEEE_DATA_BIT      0x0080
+#define DIS_ATTR_PNP_ID_BIT         0x0100
+typedef UINT16  tDIS_ATTR_MASK;
+
+#define DIS_ATTR_ALL_MASK           0xffff
+
+typedef tDIS_ATTR_MASK tDIS_ATTR_BIT ;
+
+typedef struct
+{
+    UINT16      len;
+    UINT8       *p_data;
+}tDIS_STRING;
+
+typedef struct
+{
+    UINT16       vendor_id;
+    UINT16       product_id;
+    UINT16       product_version;
+    UINT8        vendor_id_src;
+
+}tDIS_PNP_ID;
+
+typedef union
+{
+    UINT64              system_id;
+    tDIS_PNP_ID         pnp_id;
+    tDIS_STRING         data_str;
+}tDIS_ATTR;
+
+#define DIS_MAX_STRING_DATA     7
+
+typedef struct
+{
+    UINT16                  attr_mask;
+    UINT64                  system_id;
+    tDIS_PNP_ID             pnp_id;
+    UINT8                   *data_string[DIS_MAX_STRING_DATA];
+}tDIS_VALUE;
+
+
+typedef void (tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE *p_dis_value);
+
+/*****************************************************************************
+**  Data structure used by Battery Service
+*****************************************************************************/
+typedef struct
+{
+    BD_ADDR remote_bda;
+    BOOLEAN need_rsp;
+    UINT16  clt_cfg;
+}tBA_WRITE_DATA;
+
+#define BA_READ_CLT_CFG_REQ     1
+#define BA_READ_PRE_FMT_REQ     2
+#define BA_READ_RPT_REF_REQ     3
+#define BA_READ_LEVEL_REQ       4
+#define BA_WRITE_CLT_CFG_REQ    5
+
+typedef void (tBA_CBACK)(UINT8 app_id, UINT8 event, tBA_WRITE_DATA *p_data);
+
+#define BA_LEVEL_NOTIFY         0x01
+#define BA_LEVEL_PRE_FMT        0x02
+#define BA_LEVEL_RPT_REF        0x04
+typedef UINT8   tBA_LEVEL_DESCR;
+
+typedef struct
+{
+    BOOLEAN         is_pri;
+    tBA_LEVEL_DESCR     ba_level_descr;
+    tGATT_TRANSPORT transport;
+    tBA_CBACK       *p_cback;
+
+}tBA_REG_INFO;
+
+typedef union
+{
+    UINT8       ba_level;
+    UINT16      clt_cfg;
+    tGATT_CHAR_RPT_REF  rpt_ref;
+    tGATT_CHAR_PRES     pres_fmt;
+}tBA_RSP_DATA;
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*****************************************************************************
+**  Service Engine API
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function         srvc_eng_init
+**
+** Description      Initializa the GATT Service engine, register a GATT application
+**                  as for a central service management.
+**
+*******************************************************************************/
+    GATT_API extern tGATT_STATUS srvc_eng_init (void);
+
+
+/*****************************************************************************
+**  DIS Server Function
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         DIS_SrInit
+**
+** Description      Initializa the Device Information Service Server.
+**
+*******************************************************************************/
+    GATT_API extern tDIS_STATUS DIS_SrInit (tDIS_ATTR_MASK dis_attr_mask);
+/*******************************************************************************
+**
+** Function         DIS_SrUpdate
+**
+** Description      Update the DIS server attribute values
+**
+*******************************************************************************/
+    GATT_API extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info);
+/*****************************************************************************
+**  DIS Client Function
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function         DIS_ReadDISInfo
+**
+** Description      Read remote device DIS information.
+**
+** Returns          void
+**
+*******************************************************************************/
+    GATT_API extern BOOLEAN DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback);
+
+/*******************************************************************************
+**      BATTERY SERVICE API
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function         Battery_Instantiate
+**
+** Description      Instantiate a Battery service
+**
+*******************************************************************************/
+    GATT_API extern UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info);
+
+/*******************************************************************************
+**
+** Function         Battery_Rsp
+**
+** Description      Respond to a battery service request
+**
+*******************************************************************************/
+    GATT_API extern void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp);
+/*******************************************************************************
+**
+** Function         Battery_Notify
+**
+** Description      Send battery level notification
+**
+*******************************************************************************/
+    GATT_API extern void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level);
+
+
+#ifdef __cplusplus
+
+}
+#endif
+
+#endif
+
+
diff --git a/stack/srvc/srvc_battery.c b/stack/srvc/srvc_battery.c
new file mode 100644
index 0000000..25db24c
--- /dev/null
+++ b/stack/srvc/srvc_battery.c
@@ -0,0 +1,394 @@
+/*****************************************************************************
+**
+**  Name:          srvc_battery.c
+**
+**  Description:   this file contains the main Battery Service over GATT
+**                 server and handling functions.
+**
+**  Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+**  Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "srvc_eng_int.h"
+#include "srvc_battery_int.h"
+
+#if BLE_INCLUDED == TRUE
+
+#define BA_MAX_CHAR_NUM          1
+#define BA_MAX_ATTR_NUM          (BA_MAX_CHAR_NUM * 5 + 1) /* max 3 descriptors, 1 desclration and 1 value */
+
+#ifndef BATTER_LEVEL_PROP
+#define BATTER_LEVEL_PROP           (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)
+#endif
+
+
+#ifndef BATTER_LEVEL_PERM
+#define BATTER_LEVEL_PERM           (GATT_PERM_READ)
+#endif
+
+tBATTERY_CB battery_cb;
+
+
+/*******************************************************************************
+**   battery_valid_handle_range
+**
+**   validate a handle to be a DIS attribute handle or not.
+*******************************************************************************/
+BOOLEAN battery_valid_handle_range(UINT16 handle)
+{
+    UINT8       i = 0;
+    tBA_INST    *p_inst = &battery_cb.battery_inst[0];
+
+    for (;i < BA_MAX_INT_NUM; i ++, p_inst++)
+    {
+        if (handle == p_inst->ba_level_hdl ||
+            handle == p_inst->clt_cfg_hdl ||
+            handle == p_inst->rpt_ref_hdl ||
+            handle == p_inst->pres_fmt_hdl )
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+/*******************************************************************************
+**   battery_s_write_attr_value
+**
+**   Process write DIS attribute request.
+*******************************************************************************/
+UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ * p_value,
+                                 tGATT_STATUS *p_status)
+{
+    UINT8       *p = p_value->value, i;
+    UINT16      handle = p_value->handle;
+    tBA_INST    *p_inst = &battery_cb.battery_inst[0];
+    tGATT_STATUS    st = GATT_NOT_FOUND;
+    tBA_WRITE_DATA   cfg;
+    UINT8       act = SRVC_ACT_RSP;
+
+    for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
+    {
+        /* read battery level */
+        if (handle == p_inst->clt_cfg_hdl)
+        {
+            memcpy(cfg.remote_bda, srvc_eng_cb.clcb[clcb_idx].bda, BD_ADDR_LEN);
+            STREAM_TO_UINT16(cfg.clt_cfg, p);
+
+            if (p_inst->p_cback)
+            {
+                p_inst->pending_clcb_idx = clcb_idx;
+                p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
+                p_inst->pending_handle = handle;
+                cfg.need_rsp = p_value->need_rsp;
+                act = SRVC_ACT_PENDING;
+
+                (* p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg);
+            }
+        }
+        else /* all other handle is not writable */
+        {
+            st = GATT_WRITE_NOT_PERMIT;
+            break;
+        }
+    }
+    *p_status = st;
+
+    return act;
+}
+/*******************************************************************************
+**   BA Attributes Database Server Request callback
+*******************************************************************************/
+UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS* p_status)
+{
+    UINT8       i;
+    tBA_INST    *p_inst = &battery_cb.battery_inst[0];
+    tGATT_STATUS    st = GATT_NOT_FOUND;
+    UINT8       act = SRVC_ACT_RSP;
+
+        for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
+        {
+            /* read battery level */
+        if (handle == p_inst->ba_level_hdl ||
+            handle == p_inst->clt_cfg_hdl ||
+            handle == p_inst->rpt_ref_hdl ||
+            handle == p_inst->pres_fmt_hdl)
+            {
+            if (is_long)
+                st = GATT_NOT_LONG;
+
+                if (p_inst->p_cback)
+                {
+                if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ;
+                if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
+                if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
+                if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
+
+                    p_inst->pending_clcb_idx = clcb_idx;
+                    p_inst->pending_handle = handle;
+                    act = SRVC_ACT_PENDING;
+
+                (* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
+                }
+            else /* application is not registered */
+                st = GATT_ERR_UNLIKELY;
+                break;
+            }
+        /* else attribute not found */
+    }
+
+
+    *p_status = st;
+    return act;
+}
+
+
+/*******************************************************************************
+**
+** Function         battery_gatt_c_read_ba_req
+**
+** Description      Read remote device BA level attribute request.
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN battery_gatt_c_read_ba_req(UINT16 conn_id)
+{
+    return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function         battery_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void battery_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                              tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function         Battery_Instantiate
+**
+** Description      Instantiate a Battery service
+**
+*******************************************************************************/
+UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info)
+{
+    tBT_UUID            uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
+    UINT16              srvc_hdl;
+    tGATT_STATUS        status = GATT_ERROR;
+    tBA_INST            *p_inst;
+    tGATT_CHAR_PROP     prop = GATT_CHAR_PROP_BIT_READ;
+
+    if (battery_cb.inst_id == BA_MAX_INT_NUM)
+    {
+        GATT_TRACE_ERROR0("MAX battery service has been reached");
+        return 0;
+    }
+
+    p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
+
+    srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if ,
+                                            &uuid,
+                                            battery_cb.inst_id ,
+                                            BA_MAX_ATTR_NUM,
+                                            p_reg_info->is_pri);
+
+    if (srvc_hdl == 0)
+    {
+        GATT_TRACE_ERROR0("Can not create service, Battery_Instantiate() failed!");
+        return 0;
+    }
+
+    battery_cb.inst_id ++;
+
+    p_inst->app_id  =   app_id;
+    p_inst->p_cback =   p_reg_info->p_cback;
+
+    /* add battery level
+    */
+    uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL;
+
+    if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
+        prop |= GATT_CHAR_PROP_BIT_NOTIFY;
+
+    if ((p_inst->ba_level_hdl  = GATTS_AddCharacteristic(srvc_hdl,
+                                                &uuid,
+                                                BATTER_LEVEL_PERM,
+                                                prop)) == 0)
+    {
+        GATT_TRACE_ERROR0("Can not add Battery Level, Battery_Instantiate() failed!");
+        status = GATT_ERROR;
+    }
+    else
+    {
+        if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
+        {
+            uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
+            p_inst->clt_cfg_hdl  = GATTS_AddCharDescriptor(srvc_hdl,
+                                                           (GATT_PERM_READ|GATT_PERM_WRITE),
+                                                           &uuid);
+            if (p_inst->clt_cfg_hdl == 0)
+            {
+                GATT_TRACE_ERROR0("Add battery level client notification FAILED!");
+            }
+        }
+        /* need presentation format descriptor? */
+        if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT)
+        {
+            uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
+            if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl,
+                                                                 GATT_PERM_READ,
+                                                                 &uuid))
+                                       == 0)
+            {
+                GATT_TRACE_ERROR0("Add battery level presentation format descriptor FAILED!");
+            }
+
+        }
+        /* need presentation format descriptor? */
+        if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF)
+        {
+            uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
+            if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl,
+                                                                GATT_PERM_READ,
+                                                                &uuid))
+                                       == 0)
+            {
+                GATT_TRACE_ERROR0("Add battery level report reference descriptor FAILED!");
+            }
+
+        }
+        /* start service
+        */
+        status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport);
+    }
+
+    if (status != GATT_SUCCESS)
+    {
+        battery_cb.inst_id --;
+        uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY;
+        GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id);
+        srvc_hdl = 0;
+    }
+
+    return srvc_hdl;
+}
+/*******************************************************************************
+**
+** Function         Battery_Rsp
+**
+** Description      Respond to a battery service request
+**
+*******************************************************************************/
+void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp)
+{
+    tBA_INST *p_inst = &battery_cb.battery_inst[0];
+    tGATTS_RSP  rsp;
+    UINT8   *pp;
+
+    UINT8   i = 0;
+    while (i < BA_MAX_INT_NUM)
+    {
+        if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
+            break;
+        i ++;
+    }
+
+    if (i == BA_MAX_INT_NUM)
+        return;
+
+    memset(&rsp, 0, sizeof(tGATTS_RSP));
+
+    if (p_inst->pending_evt == event)
+    {
+        switch (event)
+        {
+        case BA_READ_CLT_CFG_REQ:
+            rsp.attr_value.handle = p_inst->pending_handle;
+            rsp.attr_value.len = 2;
+            pp = rsp.attr_value.value;
+            UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+            break;
+
+        case BA_READ_LEVEL_REQ:
+            rsp.attr_value.handle = p_inst->pending_handle;
+            rsp.attr_value.len = 1;
+            pp = rsp.attr_value.value;
+            UINT8_TO_STREAM(pp, p_rsp->ba_level);
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+            break;
+
+        case BA_WRITE_CLT_CFG_REQ:
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
+            break;
+
+        case BA_READ_RPT_REF_REQ:
+            rsp.attr_value.handle = p_inst->pending_handle;
+            rsp.attr_value.len = 2;
+            pp = rsp.attr_value.value;
+            UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
+            UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+            break;
+
+        default:
+            break;
+        }
+        p_inst->pending_clcb_idx = 0;
+        p_inst->pending_evt = 0;
+        p_inst->pending_handle = 0;
+    }
+    return;
+}
+/*******************************************************************************
+**
+** Function         Battery_Notify
+**
+** Description      Send battery level notification
+**
+*******************************************************************************/
+void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level)
+{
+    tBA_INST *p_inst = &battery_cb.battery_inst[0];
+    UINT8    i = 0;
+
+    while (i < BA_MAX_INT_NUM)
+    {
+        if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
+            break;
+        i ++;
+    }
+
+    if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0)
+        return;
+
+    srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
+
+}
+/*******************************************************************************
+**
+** Function         Battery_ReadBatteryLevel
+**
+** Description      Read remote device Battery Level information.
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN Battery_ReadBatteryLevel(BD_ADDR peer_bda)
+{
+    /* to be implemented */
+    return TRUE;
+}
+#endif  /* BLE_INCLUDED */
diff --git a/stack/srvc/srvc_battery_int.h b/stack/srvc/srvc_battery_int.h
new file mode 100644
index 0000000..97c808a
--- /dev/null
+++ b/stack/srvc/srvc_battery_int.h
@@ -0,0 +1,75 @@
+/*****************************************************************************
+**
+**  Name:          srvc_battery_int.h
+**
+**  Description:   this file contains the Battery service internal interface
+**                 definitions.
+**
+**
+**  Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+**  WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#ifndef SRVC_BATTERY_INT_H
+#define SRVC_BATTERY_INT_H
+
+#include "bt_target.h"
+#include "srvc_api.h"
+#include "gatt_api.h"
+
+#ifndef BA_MAX_INT_NUM
+#define BA_MAX_INT_NUM     4
+#endif
+
+#define BATTERY_LEVEL_SIZE      1
+
+
+typedef struct
+{
+    UINT8           app_id;
+    UINT16          ba_level_hdl;
+    UINT16          clt_cfg_hdl;
+    UINT16          rpt_ref_hdl;
+    UINT16          pres_fmt_hdl;
+
+    tBA_CBACK       *p_cback;
+
+    UINT16          pending_handle;
+    UINT8           pending_clcb_idx;
+    UINT8           pending_evt;
+
+}tBA_INST;
+
+typedef struct
+{
+    tBA_INST                battery_inst[BA_MAX_INT_NUM];
+    UINT8                   inst_id;
+    BOOLEAN                 enabled;
+
+}tBATTERY_CB;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global GATT data */
+#if GATT_DYNAMIC_MEMORY == FALSE
+GATT_API extern tBATTERY_CB battery_cb;
+#else
+GATT_API extern tBATTERY_CB *battery_cb_ptr;
+#define battery_cb (*battery_cb_ptr)
+#endif
+
+
+extern BOOLEAN battery_valid_handle_range(UINT16 handle);
+
+extern UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ * p_value,
+                                 tGATT_STATUS *p_status);
+extern UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS* p_status);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/stack/srvc/srvc_dis.c b/stack/srvc/srvc_dis.c
new file mode 100644
index 0000000..505d791
--- /dev/null
+++ b/stack/srvc/srvc_dis.c
@@ -0,0 +1,451 @@
+/*****************************************************************************
+**
+**  Name:          srvc_dis.c
+**
+**  Description:   this file contains the main Device Information Service over GATT
+**                 server/client and request handling functions.
+**
+**  Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+**  Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "srvc_eng_int.h"
+#include "srvc_dis_int.h"
+
+#if BLE_INCLUDED == TRUE
+
+#define DIS_UUID_TO_ATTR_MASK(x)   (UINT16)(1 << ((x) - GATT_UUID_SYSTEM_ID))
+
+#define DIS_MAX_NUM_INC_SVR       0
+#define DIS_MAX_CHAR_NUM          9
+#define DIS_MAX_ATTR_NUM          (DIS_MAX_CHAR_NUM * 2 + DIS_MAX_NUM_INC_SVR + 1)
+
+#ifndef DIS_ATTR_DB_SIZE
+#define DIS_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(DIS_MAX_NUM_INC_SVR, DIS_MAX_CHAR_NUM, 0)
+#endif
+
+#define UINT64_TO_STREAM(p, u64) {*(p)++ = (UINT8)(u64);       *(p)++ = (UINT8)((u64) >> 8);*(p)++ = (UINT8)((u64) >> 16); *(p)++ = (UINT8)((u64) >> 24); \
+                                    *(p)++ = (UINT8)((u64) >> 32); *(p)++ = (UINT8)((u64) >> 40);*(p)++ = (UINT8)((u64) >> 48); *(p)++ = (UINT8)((u64) >> 56);}
+
+#define STREAM_TO_UINT64(u64, p) {u64 = (((UINT64)(*(p))) + ((((UINT64)(*((p) + 1)))) << 8) + ((((UINT64)(*((p) + 2)))) << 16) + ((((UINT64)(*((p) + 3)))) << 24) \
+                                  + ((((UINT64)(*((p) + 4)))) << 32) + ((((UINT64)(*((p) + 5)))) << 40) + ((((UINT64)(*((p) + 6)))) << 48) + ((((UINT64)(*((p) + 7)))) << 56)); (p) += 8;}
+
+
+
+static const UINT16  dis_attr_uuid[DIS_MAX_CHAR_NUM] =
+{
+    GATT_UUID_SYSTEM_ID,
+    GATT_UUID_MODEL_NUMBER_STR,
+    GATT_UUID_SERIAL_NUMBER_STR,
+    GATT_UUID_FW_VERSION_STR,
+    GATT_UUID_HW_VERSION_STR,
+    GATT_UUID_SW_VERSION_STR,
+    GATT_UUID_MANU_NAME,
+    GATT_UUID_IEEE_DATA,
+    GATT_UUID_PNP_ID
+};
+
+tDIS_CB dis_cb;
+/*******************************************************************************
+**   dis_valid_handle_range
+**
+**   validate a handle to be a DIS attribute handle or not.
+*******************************************************************************/
+BOOLEAN dis_valid_handle_range(UINT16 handle)
+{
+    if (handle >= dis_cb.service_handle && handle <= dis_cb.max_handle)
+        return TRUE;
+    else
+        return FALSE;
+}
+/*******************************************************************************
+**   dis_write_attr_value
+**
+**   Process write DIS attribute request.
+*******************************************************************************/
+UINT8 dis_write_attr_value(tGATT_WRITE_REQ * p_data, tGATT_STATUS *p_status)
+{
+    *p_status = GATT_WRITE_NOT_PERMIT;
+    return SRVC_ACT_RSP;
+}
+/*******************************************************************************
+**   DIS Attributes Database Server Request callback
+*******************************************************************************/
+UINT8 dis_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value,
+                           BOOLEAN is_long, tGATT_STATUS *p_status)
+{
+    tDIS_DB_ENTRY   *p_db_attr = dis_cb.dis_attr;
+    UINT8           *p = p_value->value, i, *pp;
+    UINT16          offset = p_value->offset;
+    UINT8           act = SRVC_ACT_RSP;
+    tGATT_STATUS    st = GATT_NOT_FOUND;
+
+    for (i = 0; i < DIS_MAX_CHAR_NUM; i ++, p_db_attr ++)
+    {
+        if (handle == p_db_attr->handle)
+        {
+            if ((p_db_attr->uuid == GATT_UUID_PNP_ID || p_db_attr->uuid == GATT_UUID_SYSTEM_ID)&&
+                is_long == TRUE)
+            {
+                st = GATT_NOT_LONG;
+                break;
+            }
+            st = GATT_SUCCESS;
+
+            switch (p_db_attr->uuid)
+            {
+                case GATT_UUID_MANU_NAME:
+                case GATT_UUID_MODEL_NUMBER_STR:
+                case GATT_UUID_SERIAL_NUMBER_STR:
+                case GATT_UUID_FW_VERSION_STR:
+                case GATT_UUID_HW_VERSION_STR:
+                case GATT_UUID_SW_VERSION_STR:
+                case GATT_UUID_IEEE_DATA:
+                    pp = dis_cb.dis_value.data_string[p_db_attr->uuid - GATT_UUID_MODEL_NUMBER_STR];
+                    if (pp != NULL)
+                    {
+                        if (strlen ((char *)pp) > GATT_MAX_ATTR_LEN)
+                            p_value->len = GATT_MAX_ATTR_LEN;
+                        else
+                            p_value->len = (UINT16)strlen ((char *)pp);
+                    }
+                    else
+                        p_value->len = 0;
+
+                    if (offset > p_value->len)
+                    {
+                        st = GATT_INVALID_OFFSET;
+                        break;
+                    }
+                    else
+                    {
+                        p_value->len -= offset;
+                        pp += offset;
+                        ARRAY_TO_STREAM(p, pp, p_value->len);
+                        GATT_TRACE_EVENT1("GATT_UUID_MANU_NAME len=0x%04x", p_value->len);
+                    }
+                    break;
+
+
+                case GATT_UUID_SYSTEM_ID:
+                    UINT64_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */
+                    p_value->len = DIS_SYSTEM_ID_SIZE;
+                    break;
+
+                case  GATT_UUID_PNP_ID:
+                    UINT8_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id_src);
+                    UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id);
+                    UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_id);
+                    UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_version);
+                    p_value->len = DIS_PNP_ID_SIZE;
+                    break;
+
+            }
+            break;
+        }
+    }
+    *p_status = st;
+    return act;
+}
+
+/*******************************************************************************
+**
+** Function         dis_gatt_c_read_dis_value_cmpl
+**
+** Description      Client read DIS database complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void dis_gatt_c_read_dis_value_cmpl(UINT16 conn_id)
+{
+    tSRVC_CLCB *p_clcb =  srvc_eng_find_clcb_by_conn_id(conn_id);
+
+    dis_cb.dis_read_uuid_idx = 0xff;
+
+    srvc_eng_release_channel(conn_id);
+
+    if (dis_cb.p_read_dis_cback && p_clcb)
+    {
+        GATT_TRACE_ERROR1("dis_gatt_c_read_dis_value_cmpl: attr_mask = 0x%04x", p_clcb->dis_value.attr_mask);
+        GATT_TRACE_EVENT0("calling p_read_dis_cbackd");
+
+        (*dis_cb.p_read_dis_cback)(p_clcb->bda, &p_clcb->dis_value);
+        dis_cb.p_read_dis_cback=NULL;
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         dis_gatt_c_read_dis_req
+**
+** Description      Read remote device DIS attribute request.
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN dis_gatt_c_read_dis_req(UINT16 conn_id)
+{
+    tGATT_READ_PARAM   param;
+
+    memset(&param, 0, sizeof(tGATT_READ_PARAM));
+
+    param.service.uuid.len       = LEN_UUID_16;
+    param.service.s_handle       = 1;
+    param.service.e_handle       = 0xFFFF;
+    param.service.auth_req       = 0;
+
+    while (dis_cb.dis_read_uuid_idx < DIS_MAX_CHAR_NUM)
+    {
+        param.service.uuid.uu.uuid16 = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+
+        if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS)
+        {
+            return(TRUE);
+        }
+        else
+        {
+            GATT_TRACE_ERROR1 ("Read DISInfo: 0x%04x GATT_Read Failed", param.service.uuid.uu.uuid16);
+            dis_cb.dis_read_uuid_idx ++;
+        }
+    }
+
+    dis_gatt_c_read_dis_value_cmpl(conn_id);
+
+    return(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function         dis_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                              tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+{
+    UINT16      read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+    UINT8       *pp = NULL, *p_str;
+    UINT16      conn_id = p_clcb->conn_id;
+
+    GATT_TRACE_EVENT3 ("dis_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  \
+                        read_type: 0x%04x", op, status, read_type);
+
+    if (op != GATTC_OPTYPE_READ)
+        return;
+
+    if (p_data != NULL && status == GATT_SUCCESS)
+    {
+        pp = p_data->att_value.value;
+
+        switch (read_type)
+        {
+            case GATT_UUID_SYSTEM_ID:
+                GATT_TRACE_EVENT0 ("DIS_ATTR_SYS_ID_BIT");
+                if (p_data->att_value.len == DIS_SYSTEM_ID_SIZE)
+                {
+                    p_clcb->dis_value.attr_mask |= DIS_ATTR_SYS_ID_BIT;
+                    /* save system ID*/
+                    STREAM_TO_UINT64 (p_clcb->dis_value.system_id, pp);
+                }
+                break;
+
+            case GATT_UUID_PNP_ID:
+                if (p_data->att_value.len == DIS_PNP_ID_SIZE)
+                {
+                    p_clcb->dis_value.attr_mask |= DIS_ATTR_PNP_ID_BIT;
+                    STREAM_TO_UINT8 (p_clcb->dis_value.pnp_id.vendor_id_src, pp);
+                    STREAM_TO_UINT16 (p_clcb->dis_value.pnp_id.vendor_id, pp);
+                    STREAM_TO_UINT16 (p_clcb->dis_value.pnp_id.product_id, pp);
+                    STREAM_TO_UINT16 (p_clcb->dis_value.pnp_id.product_version, pp);
+                }
+                break;
+
+            case GATT_UUID_MODEL_NUMBER_STR:
+            case GATT_UUID_SERIAL_NUMBER_STR:
+            case GATT_UUID_FW_VERSION_STR:
+            case GATT_UUID_HW_VERSION_STR:
+            case GATT_UUID_SW_VERSION_STR:
+            case GATT_UUID_MANU_NAME:
+            case GATT_UUID_IEEE_DATA:
+                p_str = p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR];
+                if (p_str != NULL)
+                    GKI_freebuf(p_str);
+                if ((p_str = (UINT8 *)GKI_getbuf((UINT16)(p_data->att_value.len + 1))) != NULL)
+                {
+                    memset(p_str, 0, p_data->att_value.len + 1);
+                    p_clcb->dis_value.attr_mask |= DIS_UUID_TO_ATTR_MASK (read_type);
+                    memcpy(p_str, p_data->att_value.value, p_data->att_value.len);
+                }
+                break;
+
+            default:
+                    break;
+
+                break;
+        }/* end switch */
+    }/* end if */
+
+    dis_cb.dis_read_uuid_idx ++;
+
+    dis_gatt_c_read_dis_req(conn_id);
+}
+
+
+/*******************************************************************************
+**
+** Function         DIS_SrInit
+**
+** Description      Initializa the Device Information Service Server.
+**
+*******************************************************************************/
+tDIS_STATUS DIS_SrInit (tDIS_ATTR_MASK dis_attr_mask)
+{
+    tBT_UUID          uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
+    UINT16            i = 0;
+    tGATT_STATUS      status;
+    tDIS_DB_ENTRY        *p_db_attr = &dis_cb.dis_attr[0];
+
+    if (dis_cb.enabled)
+    {
+        GATT_TRACE_ERROR0("DIS already initalized");
+        return DIS_SUCCESS;
+    }
+
+    memset(&dis_cb, 0, sizeof(tDIS_CB));
+
+    dis_cb.service_handle = GATTS_CreateService (srvc_eng_cb.gatt_if , &uuid, 0, DIS_MAX_ATTR_NUM, TRUE);
+
+    if (dis_cb.service_handle == 0)
+    {
+        GATT_TRACE_ERROR0("Can not create service, DIS_Init failed!");
+        return GATT_ERROR;
+    }
+    dis_cb.max_handle = dis_cb.service_handle + DIS_MAX_ATTR_NUM;
+
+    while (dis_attr_mask != 0 && i < DIS_MAX_CHAR_NUM)
+    {
+        /* add Manufacturer name
+        */
+        uuid.uu.uuid16 = p_db_attr->uuid = dis_attr_uuid[i];
+        p_db_attr->handle  = GATTS_AddCharacteristic(dis_cb.service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ);
+        GATT_TRACE_DEBUG2 ("DIS_SrInit:  handle of new attribute 0x%04 = x%d", uuid.uu.uuid16, p_db_attr->handle  );
+        p_db_attr ++;
+        i ++;
+        dis_attr_mask >>= 1;
+    }
+
+    /* start service
+    */
+    status = GATTS_StartService (srvc_eng_cb.gatt_if, dis_cb.service_handle, GATT_TRANSPORT_LE_BR_EDR);
+
+    dis_cb.enabled = TRUE;
+
+    return (tDIS_STATUS) status;
+}
+/*******************************************************************************
+**
+** Function         DIS_SrUpdate
+**
+** Description      Update the DIS server attribute values
+**
+*******************************************************************************/
+tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info)
+{
+    UINT8           i = 1;
+    tDIS_STATUS     st = DIS_SUCCESS;
+
+    if (dis_attr_bit & DIS_ATTR_SYS_ID_BIT)
+    {
+        dis_cb.dis_value.system_id = p_info->system_id;
+    }
+    else if (dis_attr_bit & DIS_ATTR_PNP_ID_BIT)
+    {
+        dis_cb.dis_value.pnp_id.vendor_id         = p_info->pnp_id.vendor_id;
+        dis_cb.dis_value.pnp_id.vendor_id_src     = p_info->pnp_id.vendor_id_src;
+        dis_cb.dis_value.pnp_id.product_id        = p_info->pnp_id.product_id;
+        dis_cb.dis_value.pnp_id.product_version   = p_info->pnp_id.product_version;
+    }
+    else
+    {
+        st = DIS_ILLEGAL_PARAM;
+
+        while (dis_attr_bit && i < (DIS_MAX_CHAR_NUM -1 ))
+        {
+            if (dis_attr_bit & (UINT16)(1 << i))
+            {
+                if (dis_cb.dis_value.data_string[i - 1] != NULL)
+                    GKI_freebuf(dis_cb.dis_value.data_string[i]);
+/* coverity[OVERRUN-STATIC] False-positive : when i = 8, (1 << i) == DIS_ATTR_PNP_ID_BIT, and it will never come down here
+CID 49902: Out-of-bounds read (OVERRUN_STATIC)
+Overrunning static array "dis_cb.dis_value.data_string", with 7 elements, at position 7 with index variable "i".
+*/
+                if ((dis_cb.dis_value.data_string[i - 1] = (UINT8 *)GKI_getbuf((UINT16)(p_info->data_str.len + 1))) != NULL)
+                {
+                    memset(dis_cb.dis_value.data_string[i - 1], 0, p_info->data_str.len + 1); /* make sure null terminate */
+                    memcpy(dis_cb.dis_value.data_string[i - 1], p_info->data_str.p_data, p_info->data_str.len);
+                    st = DIS_SUCCESS;
+                }
+                else
+                    st = DIS_NO_RESOURCES;
+
+                break;
+            }
+            i ++;
+        }
+    }
+    return st;
+}
+/*******************************************************************************
+**
+** Function         DIS_ReadDISInfo
+**
+** Description      Read remote device DIS information.
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback)
+{
+    UINT16             conn_id;
+
+    /* For now we only handle one at a time */
+    if (dis_cb.dis_read_uuid_idx != 0xff)
+        return(FALSE);
+
+    if (p_cback == NULL)
+        return(FALSE);
+
+    dis_cb.p_read_dis_cback = p_cback;
+    /* Mark currently active operation */
+    dis_cb.dis_read_uuid_idx = 0;
+
+    GATT_TRACE_EVENT3 ("DIS_ReadDISInfo() - BDA: %08x%04x  cl_read_uuid: 0x%04x",
+                      (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
+                      (peer_bda[4]<<8)+peer_bda[5], dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
+
+
+    GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id);
+
+    /* need to enhance it as multiple service is needed */
+    srvc_eng_request_channel(peer_bda, SRVC_ID_DIS);
+
+    if (conn_id == GATT_INVALID_CONN_ID)
+    {
+        return GATT_Connect(srvc_eng_cb.gatt_if, peer_bda, TRUE);
+    }
+
+    return dis_gatt_c_read_dis_req(conn_id);
+
+}
+#endif  /* BLE_INCLUDED */
+
+
diff --git a/stack/srvc/srvc_dis_int.h b/stack/srvc/srvc_dis_int.h
new file mode 100644
index 0000000..ede7a85
--- /dev/null
+++ b/stack/srvc/srvc_dis_int.h
@@ -0,0 +1,76 @@
+/*****************************************************************************
+**
+**  Name:          srvc_dis_int.h
+**
+**  Description:   this file contains the GAP internal interface
+**                 definitions.
+**
+**
+**  Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+**  WIDCOMM Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#ifndef SRVC_DIS_INT_H
+#define SRVC_DIS_INT_H
+
+#include "bt_target.h"
+#include "srvc_api.h"
+#include "gatt_api.h"
+
+#define DIS_MAX_CHAR_NUM            9
+
+
+typedef struct
+{
+    UINT16      uuid;
+    UINT16      handle;
+}tDIS_DB_ENTRY;
+
+#define DIS_SYSTEM_ID_SIZE      8
+#define DIS_PNP_ID_SIZE         7
+
+
+
+typedef struct
+{
+    tDIS_DB_ENTRY           dis_attr[DIS_MAX_CHAR_NUM];
+    tDIS_VALUE              dis_value;
+
+    tDIS_READ_CBACK         *p_read_dis_cback;
+
+    UINT16                  service_handle;
+    UINT16                  max_handle;
+
+    BOOLEAN                 enabled;
+
+    UINT8                   dis_read_uuid_idx;
+}tDIS_CB;
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global GATT data */
+#if GATT_DYNAMIC_MEMORY == FALSE
+GATT_API extern tDIS_CB dis_cb;
+#else
+GATT_API extern tDIS_CB *dis_cb_ptr;
+#define dis_cb (*dis_cb_ptr)
+#endif
+
+
+extern BOOLEAN dis_valid_handle_range(UINT16 handle);
+extern UINT8 dis_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value,
+                           BOOLEAN is_long, tGATT_STATUS *p_status);
+extern UINT8 dis_write_attr_value(tGATT_WRITE_REQ * p_data, tGATT_STATUS *p_status);
+
+extern void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                                    tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/stack/srvc/srvc_eng.c b/stack/srvc/srvc_eng.c
new file mode 100644
index 0000000..c4f5527
--- /dev/null
+++ b/stack/srvc/srvc_eng.c
@@ -0,0 +1,456 @@
+/*****************************************************************************
+**
+**  Name:          srvc_eng.c
+**
+**  Description:   this file contains the main Device Information Service over GATT
+**                 server/client and request handling functions.
+**
+**  Copyright (c) 2008-2011, Broadcom Corp., All Rights Reserved.
+**  Broadcom Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#include "bt_target.h"
+
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "srvc_eng_int.h"
+
+#if BLE_INCLUDED == TRUE
+
+//#if DIS_INCLUDED == TRUE
+#include "srvc_dis_int.h"
+//#endif
+#include "srvc_battery_int.h"
+
+static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data);
+static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason);
+static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+static tGATT_CBACK srvc_gatt_cback =
+{
+    srvc_eng_connect_cback,
+    srvc_eng_c_cmpl_cback,
+    NULL,
+    NULL,
+    srvc_eng_s_request_cback
+} ;
+/* type for action functions */
+typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                                    tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] =
+{
+    dis_c_cmpl_cback,
+};
+
+tSRVC_ENG_CB srvc_eng_cb;
+
+/*******************************************************************************
+**
+** Function         srvc_eng_find_conn_id_by_bd_addr
+**
+** Description      The function searches all LCB with macthing bd address
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+UINT16 srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda)
+{
+    UINT8 i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+        {
+            return p_clcb->conn_id;
+        }
+    }
+
+    return GATT_INVALID_CONN_ID;
+}
+
+/*******************************************************************************
+**
+** Function         srvc_eng_find_clcb_by_bd_addr
+**
+** Description      The function searches all LCBs with macthing bd address.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda)
+{
+    UINT8 i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+        {
+            return p_clcb;
+        }
+    }
+
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_find_clcb_by_conn_id
+**
+** Description      The function searches all LCBs with macthing connection ID.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(UINT16 conn_id)
+{
+    UINT8 i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
+        {
+            return p_clcb;
+        }
+    }
+
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_find_clcb_by_conn_id
+**
+** Description      The function searches all LCBs with macthing connection ID.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+UINT8 srvc_eng_find_clcb_idx_by_conn_id(UINT16 conn_id)
+{
+    UINT8 i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
+        {
+            return i_clcb;
+        }
+    }
+
+    return SRVC_MAX_APPS;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_clcb_alloc
+**
+** Description      The function allocates a GATT profile  connection link control block
+**
+** Returns           NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tSRVC_CLCB *srvc_eng_clcb_alloc (UINT16 conn_id, BD_ADDR bda)
+{
+    UINT8                   i_clcb = 0;
+    tSRVC_CLCB      *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (!p_clcb->in_use)
+        {
+            p_clcb->in_use      = TRUE;
+            p_clcb->conn_id     = conn_id;
+            p_clcb->connected   = TRUE;
+            memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
+            break;
+        }
+    }
+    return p_clcb;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_clcb_dealloc
+**
+** Description      The function deallocates a GATT profile  connection link control block
+**
+** Returns           NTrue the deallocation is successful
+**
+*******************************************************************************/
+BOOLEAN srvc_eng_clcb_dealloc (UINT16 conn_id)
+{
+    UINT8                   i_clcb = 0;
+    tSRVC_CLCB      *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id))
+        {
+            memset(p_clcb, 0, sizeof(tSRVC_CLCB));
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+/*******************************************************************************
+**   Service Engine Server Attributes Database Read/Read Blob Request process
+*******************************************************************************/
+UINT8 srvc_eng_process_read_req (UINT8 clcb_idx, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
+{
+    tGATT_STATUS    status = GATT_NOT_FOUND;
+    UINT8       act = SRVC_ACT_RSP;
+
+    if (p_data->is_long)
+        p_rsp->attr_value.offset = p_data->offset;
+
+    p_rsp->attr_value.handle = p_data->handle;
+
+    if (dis_valid_handle_range(p_data->handle))
+        act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
+
+    else if (battery_valid_handle_range(p_data->handle))
+        act = battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
+
+    else
+        *p_status = status;
+    return act;
+}
+/*******************************************************************************
+**   Service Engine Server Attributes Database write Request process
+*******************************************************************************/
+UINT8 srvc_eng_process_write_req (UINT8 clcb_idx, tGATT_WRITE_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
+{
+    UINT8       act = SRVC_ACT_RSP;
+
+    if (dis_valid_handle_range(p_data->handle))
+    {
+        act = dis_write_attr_value(p_data, p_status);
+    }
+    else if (battery_valid_handle_range(p_data->handle))
+    {
+        act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
+    }
+    else
+        *p_status = GATT_NOT_FOUND;
+
+    return act;
+}
+
+/*******************************************************************************
+**
+** Function         srvc_eng_s_request_cback
+**
+** Description      GATT DIS attribute access request callback.
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
+                                        tGATTS_DATA *p_data)
+{
+    UINT8       status = GATT_INVALID_PDU;
+    tGATTS_RSP  rsp_msg ;
+    UINT8       act = SRVC_ACT_IGNORE;
+    UINT8   clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
+
+    GATT_TRACE_EVENT1("srvc_eng_s_request_cback : recv type (0x%02x)", type);
+
+    memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+    srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id;
+
+    switch (type)
+    {
+        case GATTS_REQ_TYPE_READ:
+            act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg, &status);
+            break;
+
+        case GATTS_REQ_TYPE_WRITE:
+            act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg, &status);
+            if (!p_data->write_req.need_rsp)
+                act = SRVC_ACT_IGNORE;
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_EXEC:
+            GATT_TRACE_EVENT0("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
+            break;
+
+        case GATTS_REQ_TYPE_MTU:
+            GATT_TRACE_EVENT1("Get MTU exchange new mtu size: %d", p_data->mtu);
+            break;
+
+        default:
+            GATT_TRACE_EVENT1("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+            break;
+    }
+
+    srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
+
+    if (act == SRVC_ACT_RSP)
+        GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function         srvc_eng_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+                                   tGATT_CL_COMPLETE *p_data)
+{
+    tSRVC_CLCB   *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
+
+    GATT_TRACE_EVENT2 ("srvc_eng_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x ", op, status);
+
+    if (p_clcb == NULL)
+    {
+        GATT_TRACE_ERROR0("srvc_eng_c_cmpl_cback received for unknown connection");
+        return;
+    }
+
+    if (p_clcb->cur_srvc_id != SRVC_ID_NONE &&
+        p_clcb->cur_srvc_id <= SRVC_ID_MAX)
+        srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data);
+}
+
+
+/*******************************************************************************
+**
+** Function         srvc_eng_connect_cback
+**
+** Description      Gatt profile connection callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
+                                        BOOLEAN connected, tGATT_DISCONN_REASON reason)
+{
+    GATT_TRACE_EVENT5 ("srvc_eng_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
+                       (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
+                       (bda[4]<<8)+bda[5], connected, conn_id, reason);
+
+    if (connected)
+    {
+        if (srvc_eng_clcb_alloc(conn_id, bda) == NULL)
+        {
+            GATT_TRACE_ERROR0 ("srvc_eng_connect_cback: no_resource");
+            return;
+        }
+    }
+    else
+    {
+        srvc_eng_clcb_dealloc(conn_id);
+    }
+
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+BOOLEAN srvc_eng_request_channel (BD_ADDR remote_bda, UINT8 srvc_id )
+{
+    BOOLEAN set = TRUE;
+    tSRVC_CLCB  *p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda);
+
+    if (p_clcb == NULL)
+        p_clcb = srvc_eng_clcb_alloc(0, remote_bda);
+
+    if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE)
+        p_clcb->cur_srvc_id = srvc_id;
+    else
+        set = FALSE;
+
+    return set;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_release_channel
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void srvc_eng_release_channel (UINT16 conn_id)
+{
+    tSRVC_CLCB *p_clcb =  srvc_eng_find_clcb_by_conn_id(conn_id);
+
+    p_clcb->cur_srvc_id = SRVC_ID_NONE;
+
+    /* check pending request */
+    //if (p_clcb->pend_req == NULL)
+        GATT_Disconnect(p_clcb->conn_id);
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_init
+**
+** Description      Initializa the GATT Service engine.
+**
+*******************************************************************************/
+tGATT_STATUS srvc_eng_init (void)
+{
+    tBT_UUID          app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
+
+    if (srvc_eng_cb.enabled)
+    {
+        GATT_TRACE_ERROR0("DIS already initalized");
+    }
+    else
+    {
+        memset(&srvc_eng_cb, 0, sizeof(tDIS_CB));
+
+        /* Create a GATT profile service */
+        srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback);
+        GATT_StartIf(srvc_eng_cb.gatt_if);
+
+        GATT_TRACE_DEBUG1 ("Srvc_Init:  gatt_if=%d  ", srvc_eng_cb.gatt_if);
+
+        srvc_eng_cb.enabled = TRUE;
+//#if DIS_INCLUDED == TRUE
+        dis_cb.dis_read_uuid_idx = 0xff;
+//#endif
+    }
+    return GATT_SUCCESS;
+}
+
+void srvc_sr_rsp(UINT8 clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp)
+{
+    if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0)
+    {
+        GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
+                  srvc_eng_cb.clcb[clcb_idx].trans_id,
+                  st,
+                  p_rsp);
+
+        srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
+    }
+}
+void srvc_sr_notify(BD_ADDR remote_bda, UINT16 handle, UINT16 len, UINT8 *p_value)
+{
+    UINT16 conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
+
+    if (conn_id != GATT_INVALID_CONN_ID)
+    {
+        GATTS_HandleValueNotification( conn_id, handle, len, p_value);
+    }
+}
+
+#endif
+
+
+
diff --git a/stack/srvc/srvc_eng_int.h b/stack/srvc/srvc_eng_int.h
new file mode 100644
index 0000000..40aae81
--- /dev/null
+++ b/stack/srvc/srvc_eng_int.h
@@ -0,0 +1,82 @@
+/*****************************************************************************
+**
+**  Name:          srvc_eng_int.h
+**
+**  Description:   this file contains the Service Engine internal interface
+**                 definitions.
+**
+**
+**  Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved.
+**  Broadcom Corp. Bluetooth Core. Proprietary and confidential.
+******************************************************************************/
+
+#ifndef SRVC_ENG_INT_H
+#define SRVC_ENG_INT_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "srvc_api.h"
+
+#define SRVC_MAX_APPS                  GATT_CL_MAX_LCB
+
+#define SRVC_ID_NONE            0
+#define SRVC_ID_DIS             1
+#define SRVC_ID_MAX             SRVC_ID_DIS
+
+#define SRVC_ACT_IGNORE     0
+#define SRVC_ACT_RSP        1
+#define SRVC_ACT_PENDING    2
+
+typedef struct
+{
+    BOOLEAN         in_use;
+    UINT16          conn_id;
+    BOOLEAN         connected;
+    BD_ADDR         bda;
+    UINT32          trans_id;
+    UINT8           cur_srvc_id;
+
+    tDIS_VALUE      dis_value;
+
+}tSRVC_CLCB;
+
+
+/* service engine control block */
+typedef struct
+{
+    tSRVC_CLCB              clcb[SRVC_MAX_APPS]; /* connection link*/
+    tGATT_IF                gatt_if;
+    BOOLEAN                 enabled;
+
+}tSRVC_ENG_CB;
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global GATT data */
+#if GATT_DYNAMIC_MEMORY == FALSE
+GATT_API extern tSRVC_ENG_CB srvc_eng_cb;
+#else
+GATT_API extern tSRVC_ENG_CB srvc_eng_cb_ptr;
+#define srvc_eng_cb (*srvc_eng_cb_ptr)
+
+#endif
+
+extern tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(UINT16 conn_id);
+extern tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda);
+extern UINT16 srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda);
+
+
+extern void srvc_eng_release_channel (UINT16 conn_id) ;
+extern BOOLEAN srvc_eng_request_channel (BD_ADDR remote_bda, UINT8 srvc_id );
+extern void srvc_sr_rsp(UINT8 clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp);
+extern void srvc_sr_notify(BD_ADDR remote_bda, UINT16 handle, UINT16 len, UINT8 *p_value);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif