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(¶m, 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, ¶m) == 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