From fa50365a28a42a8171e733dca883284e91f6595d Mon Sep 17 00:00:00 2001 From: Atul Rai Date: Fri, 8 Jul 2016 14:32:41 +0900 Subject: [PATCH] [Adapt] Add HID connection/disconnection handling This patch adds HID Host profile implementation in bt-service. It adds implementation for HIDHost profile enable, HID Host connect/disconnect APIs and callback event handling in bt-service. Change-Id: I8cae531d126536987c3d8554fab59036c7efa746 Signed-off-by: Atul Rai --- bt-service-adaptation/CMakeLists.txt | 1 + .../services/adapter/bt-service-core-adapter.c | 24 +- .../services/bt-request-handler.c | 39 ++ .../services/bt-service-event-receiver.c | 50 ++- .../services/hid/bt-service-hidhost.c | 423 +++++++++++++++++++++ .../services/include/bt-service-event-receiver.h | 1 + .../services/include/bt-service-hidhost.h | 41 ++ 7 files changed, 562 insertions(+), 17 deletions(-) create mode 100644 bt-service-adaptation/services/hid/bt-service-hidhost.c create mode 100644 bt-service-adaptation/services/include/bt-service-hidhost.h diff --git a/bt-service-adaptation/CMakeLists.txt b/bt-service-adaptation/CMakeLists.txt index c31a52a..524dee2 100644 --- a/bt-service-adaptation/CMakeLists.txt +++ b/bt-service-adaptation/CMakeLists.txt @@ -14,6 +14,7 @@ marshal.c ./services/bt-service-event-receiver.c ./services/bt-service-dpm.c ./services/bt-service-agent-util.c +./services/hid/bt-service-hidhost.c ) IF("${CMAKE_BUILD_TYPE}" STREQUAL "") diff --git a/bt-service-adaptation/services/adapter/bt-service-core-adapter.c b/bt-service-adaptation/services/adapter/bt-service-core-adapter.c index bc6f43a..78525f2 100644 --- a/bt-service-adaptation/services/adapter/bt-service-core-adapter.c +++ b/bt-service-adaptation/services/adapter/bt-service-core-adapter.c @@ -44,6 +44,7 @@ #ifdef TIZEN_DPM_ENABLE #include "bt-service-dpm.h" #endif +#include "bt-service-hidhost.h" /* OAL headers */ #include @@ -681,11 +682,30 @@ static void __bt_adapter_event_handler(int event_type, gpointer event_data) BT_DBG("-"); } +static int __bt_init_profiles() +{ + int ret; + + /*TODO: Init bluetooth profiles */ + ret = _bt_hidhost_initialize(); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("_bt_hidhost_initialize Failed"); + return ret; + } + + return BLUETOOTH_ERROR_NONE; +} + /* OAL post initialization handler */ static void __bt_post_oal_init(void) { + int ret; + BT_DBG("OAL initialized, Init profiles.."); - /*TODO */ + ret = __bt_init_profiles(); + if (ret != BLUETOOTH_ERROR_NONE) + BT_ERR("Bluetooth profile init error: %d", ret); + return; } @@ -718,7 +738,7 @@ static gboolean __bt_is_service_request_present(int service_function) /* Get method invocation context */ for (l = _bt_get_invocation_list(); l != NULL; l = g_slist_next(l)) { req_info = l->data; - if (!req_info && req_info->service_function == service_function) + if (req_info && req_info->service_function == service_function) return TRUE; } diff --git a/bt-service-adaptation/services/bt-request-handler.c b/bt-service-adaptation/services/bt-request-handler.c index 7e44004..f2ebc8b 100644 --- a/bt-service-adaptation/services/bt-request-handler.c +++ b/bt-service-adaptation/services/bt-request-handler.c @@ -32,6 +32,7 @@ #ifdef TIZEN_DPM_ENABLE #include "bt-service-dpm.h" #endif +#include "bt-service-hidhost.h" /* For maintaining Application Sync API call requests */ GSList *invocation_list = NULL; @@ -592,6 +593,44 @@ int __bt_bluez_request(int function_name, result = _bt_passkey_confirmation_reply(confirmation_reply); break; } + case BT_HID_CONNECT: { + bluetooth_device_address_t address = { {0} }; + + __bt_service_get_parameters(in_param1, + &address, sizeof(bluetooth_device_address_t)); + + result = _bt_hid_connect(&address); + if (result != BLUETOOTH_ERROR_NONE) { + g_array_append_vals(*out_param1, &address, + sizeof(bluetooth_device_address_t)); + } else { + char *addr = g_malloc0(BT_ADDRESS_STRING_SIZE); + _bt_convert_addr_type_to_string(addr, address.addr); + sender = (char*)g_dbus_method_invocation_get_sender(context); + _bt_save_invocation_context(context, result, sender, + function_name, (gpointer)addr); + } + break; + } + case BT_HID_DISCONNECT: { + bluetooth_device_address_t address = { {0} }; + + __bt_service_get_parameters(in_param1, + &address, sizeof(bluetooth_device_address_t)); + + result = _bt_hid_disconnect(&address); + if (result != BLUETOOTH_ERROR_NONE) { + g_array_append_vals(*out_param1, &address, + sizeof(bluetooth_device_address_t)); + } else { + char *addr = g_malloc0(BT_ADDRESS_STRING_SIZE); + _bt_convert_addr_type_to_string(addr, address.addr); + sender = (char*)g_dbus_method_invocation_get_sender(context); + _bt_save_invocation_context(context, result, sender, + function_name, (gpointer)addr); + } + break; + } #ifdef TIZEN_DPM_ENABLE case BT_DPM_SET_ALLOW_BT_MODE: { dpm_bt_allow_t value = DPM_BT_ERROR; diff --git a/bt-service-adaptation/services/bt-service-event-receiver.c b/bt-service-adaptation/services/bt-service-event-receiver.c index 7dd7318..5f107ab 100644 --- a/bt-service-adaptation/services/bt-service-event-receiver.c +++ b/bt-service-adaptation/services/bt-service-event-receiver.c @@ -35,6 +35,7 @@ _bt_service_event_handler_callback adapter_cb; _bt_service_event_handler_callback device_cb; +_bt_service_event_handler_callback hid_cb; void _bt_service_register_event_handler_callback( bt_service_module_t module, _bt_service_event_handler_callback cb) @@ -48,6 +49,10 @@ void _bt_service_register_event_handler_callback( BT_INFO("Register BT_DEVICE_MODULE Callback"); device_cb = cb; break; + case BT_HID_MODULE: + BT_INFO("Register BT_HID_MODULE Callback"); + hid_cb = cb; + break; default: BT_INFO("Unknown module"); } @@ -60,6 +65,14 @@ void _bt_service_unregister_event_handler_callback(bt_service_module_t module) BT_INFO("Un-Register BT_ADAPTER_MODULE Callback"); adapter_cb = NULL; break; + case BT_DEVICE_MODULE: + BT_INFO("Un-Register BT_DEVICE_MODULE Callback"); + device_cb = NULL; + break; + case BT_HID_MODULE: + BT_INFO("Un-Register BT_HID_MODULE Callback"); + hid_cb = NULL; + break; default: BT_INFO("Unknown module"); } @@ -88,24 +101,31 @@ void _bt_service_oal_event_receiver(int event_type, gpointer event_data, gsize l if (adapter_cb) adapter_cb(event_type, event_data); break; - case OAL_EVENT_ADAPTER_INQUIRY_RESULT_BREDR_ONLY: - case OAL_EVENT_ADAPTER_INQUIRY_RESULT_BLE: + case OAL_EVENT_ADAPTER_INQUIRY_RESULT_BREDR_ONLY: + case OAL_EVENT_ADAPTER_INQUIRY_RESULT_BLE: + case OAL_EVENT_DEVICE_BONDING_SUCCESS: + case OAL_EVENT_DEVICE_BONDING_REMOVED: + case OAL_EVENT_DEVICE_BONDING_FAILED: + case OAL_EVENT_DEVICE_ACL_CONNECTED: + case OAL_EVENT_DEVICE_ACL_DISCONNECTED: + case OAL_EVENT_DEVICE_PIN_REQUEST: + case OAL_EVENT_DEVICE_PASSKEY_ENTRY_REQUEST: + case OAL_EVENT_DEVICE_PASSKEY_CONFIRMATION_REQUEST: + case OAL_EVENT_DEVICE_PASSKEY_DISPLAY: + case OAL_EVENT_DEVICE_SSP_CONSENT_REQUEST: + if (device_cb) + device_cb(event_type, event_data); + break; case OAL_EVENT_DEVICE_PROPERTIES: + if (hid_cb) + hid_cb(event_type, event_data); if (device_cb) - device_cb(event_type, event_data); + device_cb(event_type, event_data); break; - case OAL_EVENT_DEVICE_BONDING_SUCCESS: - case OAL_EVENT_DEVICE_BONDING_REMOVED: - case OAL_EVENT_DEVICE_BONDING_FAILED: - case OAL_EVENT_DEVICE_ACL_CONNECTED: - case OAL_EVENT_DEVICE_ACL_DISCONNECTED: - case OAL_EVENT_DEVICE_PIN_REQUEST: - case OAL_EVENT_DEVICE_PASSKEY_ENTRY_REQUEST: - case OAL_EVENT_DEVICE_PASSKEY_CONFIRMATION_REQUEST: - case OAL_EVENT_DEVICE_PASSKEY_DISPLAY: - case OAL_EVENT_DEVICE_SSP_CONSENT_REQUEST: - if (device_cb) - device_cb(event_type, event_data); + case OAL_EVENT_HID_CONNECTED: + case OAL_EVENT_HID_DISCONNECTED: + if (hid_cb) + hid_cb(event_type, event_data); break; default: BT_ERR("Unhandled Event: %d", event_type); diff --git a/bt-service-adaptation/services/hid/bt-service-hidhost.c b/bt-service-adaptation/services/hid/bt-service-hidhost.c new file mode 100644 index 0000000..6fd0891 --- /dev/null +++ b/bt-service-adaptation/services/hid/bt-service-hidhost.c @@ -0,0 +1,423 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Atul Kumar Rai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + +#include "bluetooth-api.h" +#include "bt-internal-types.h" +#include "bt-request-handler.h" +#include "bt-service-util.h" +#include "bt-service-event.h" +#include "bt-service-hidhost.h" +#include "bt-service-common.h" +#include "bt-service-event-receiver.h" +#include "oal-event.h" +#include "oal-device-mgr.h" +#include "oal-hid-host.h" + +typedef struct { + char address[BT_ADDRESS_STRING_SIZE]; + bt_remote_dev_info_t *dev_info; +} bt_connected_hid_dev_info_t; + +enum { + HID_DEV_INFO_NONE, + HID_DEV_INFO_ADDED, + HID_DEV_INFO_UPDATED +}; + +static GList *g_connected_list; + +static invocation_info_t* __bt_get_request_info(int service_function, char *address) +{ + GSList *l; + invocation_info_t *req_info = NULL; + + BT_DBG("+"); + + retv_if(NULL == address, FALSE); + + /* Get method invocation context */ + for (l = _bt_get_invocation_list(); l != NULL; l = g_slist_next(l)) { + req_info = l->data; + if (req_info == NULL || req_info->service_function != service_function) + continue; + + if (!strncasecmp((char *)req_info->user_data, address, BT_ADDRESS_STRING_SIZE)) + return req_info; + } + + return NULL; +} + +static gboolean __bt_is_hid_device_connected(const char *address) +{ + bt_connected_hid_dev_info_t *hid_dev_info; + GList *node; + + BT_DBG("+"); + + node = g_list_first(g_connected_list); + while (node != NULL) { + hid_dev_info = (bt_connected_hid_dev_info_t *)node->data; + + if (g_strcmp0(hid_dev_info->address, address) == 0) { + BT_ERR("Device present in the list"); + return TRUE; + } + node = g_list_next(node); + } + + return FALSE; + BT_DBG("-"); + +} + +static void __bt_add_hid_device_to_connected_list(const char *address) +{ + bt_connected_hid_dev_info_t *hid_dev_info; + + BT_DBG("+"); + + if (TRUE == __bt_is_hid_device_connected(address)) { + BT_ERR("Device already present in the list"); + return; + } + + hid_dev_info = g_malloc0(sizeof(bt_connected_hid_dev_info_t)); + g_strlcpy(hid_dev_info->address, address, sizeof(hid_dev_info->address)); + hid_dev_info->dev_info = NULL; + g_connected_list = g_list_append(g_connected_list, hid_dev_info); + + BT_DBG("-"); +} + +static void __bt_remove_hid_device_from_connected_list(const char *address) +{ + bt_connected_hid_dev_info_t *hid_dev_info; + GList *node; + + BT_DBG("+"); + + node = g_list_first(g_connected_list); + while (node != NULL) { + hid_dev_info = node->data; + if (g_strcmp0(hid_dev_info->address, address) == 0) { + BT_DBG("Address match \n"); + g_connected_list = g_list_remove(g_connected_list, hid_dev_info); + if(hid_dev_info->dev_info) + _bt_free_device_info(hid_dev_info->dev_info); + g_free(hid_dev_info); + break; + } + + node = g_list_next(node); + } + + BT_DBG("-"); +} + +static void __bt_clear_connected_device_list(void) +{ + bt_connected_hid_dev_info_t *hid_dev_info; + GList *node; + + BT_DBG("+"); + + node = g_list_first(g_connected_list); + while (node != NULL) { + hid_dev_info = node->data; + g_connected_list = g_list_remove(g_connected_list, hid_dev_info); + if(hid_dev_info->dev_info) + _bt_free_device_info(hid_dev_info->dev_info); + g_free(hid_dev_info); + node = g_list_next(node); + } + + g_connected_list = NULL; + BT_DBG("-"); +} + +static int __bt_update_hid_device_info(bt_remote_dev_info_t *rem_info) +{ + int ret = HID_DEV_INFO_NONE; + bt_connected_hid_dev_info_t *hid_dev_info; + GList *node; + + BT_DBG("+"); + + node = g_list_first(g_connected_list); + while (node != NULL) { + hid_dev_info = node->data; + if (g_strcmp0(hid_dev_info->address, rem_info->address) != 0) { + node = g_list_next(node); + continue; + } + + BT_DBG("Address match, Device present in the list"); + if(hid_dev_info->dev_info == NULL) { + hid_dev_info->dev_info = rem_info; + return HID_DEV_INFO_ADDED; + } + return ret; + } + + return ret; +} + +static void __bt_handle_hid_connection(char *address) +{ + bt_address_t bd_addr; + + BT_DBG("+"); + + ret_if(NULL == address); + + memset(&bd_addr, 0x00, sizeof(bt_address_t)); + _bt_convert_addr_string_to_type(bd_addr.addr, address); + + device_query_attributes(&bd_addr); + __bt_add_hid_device_to_connected_list(address); + + BT_DBG("-"); +} + +static void __bt_handle_hid_disconnection(char *address) +{ + int result = BLUETOOTH_ERROR_NONE; + GVariant *param; + + BT_DBG("+"); + + ret_if(NULL == address); + + /* Remove HID device from connected list */ + __bt_remove_hid_device_from_connected_list(address); + + /* Send HID disconnected event to Application */ + param = g_variant_new("(is)", result, address); + _bt_send_event(BT_HID_EVENT, BLUETOOTH_HID_DISCONNECTED, param); + + BT_DBG("-"); +} + +static void __bt_handle_device_properties(bt_remote_dev_info_t *rem_info) +{ + int ret; + int result = BLUETOOTH_ERROR_NONE; + GVariant *param; + + BT_DBG("+"); + + /* Update HID device info in connected list */ + ret = __bt_update_hid_device_info(rem_info); + if (HID_DEV_INFO_ADDED == ret) { + /* Send HID connected event to Application */ + param = g_variant_new("(is)", result, rem_info->address); + _bt_send_event(BT_HID_EVENT, BLUETOOTH_HID_CONNECTED, param); + } else { + _bt_free_device_info(rem_info); + } + + BT_DBG("-"); +} + +static void __bt_hid_event_handler(int event_type, gpointer event_data) +{ + bluetooth_device_address_t device_address; + char address[BT_ADDRESS_STRING_SIZE]; + + int result = BLUETOOTH_ERROR_NONE; + + invocation_info_t *req_info; + GArray *out_param; + + BT_DBG("+"); + + switch(event_type) { + case OAL_EVENT_HID_CONNECTED: { + event_hid_conn_t *event = event_data; + + memset(&device_address, 0x00, sizeof(bluetooth_device_address_t)); + memcpy(device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH); + + memset(address, 0x00, BT_ADDRESS_STRING_SIZE); + _bt_convert_addr_type_to_string(address, event->address.addr); + + /* Reply to async request for HID connect, if any */ + req_info = __bt_get_request_info(BT_HID_CONNECT, address); + if (NULL != req_info) { + out_param = g_array_new(FALSE, FALSE, sizeof(gchar)); + g_array_append_vals(out_param, &device_address, + sizeof(bluetooth_device_address_t)); + _bt_service_method_return(req_info->context, + out_param, result); + g_array_free(out_param, TRUE); + g_free(req_info->user_data); + _bt_free_info_from_invocation_list(req_info); + } + __bt_handle_hid_connection(address); + break; + } + case OAL_EVENT_HID_DISCONNECTED: { + event_hid_conn_t *event = event_data; + + memset(&device_address, 0x00, sizeof(bluetooth_device_address_t)); + memcpy(device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH); + + memset(address, 0x00, BT_ADDRESS_STRING_SIZE); + _bt_convert_addr_type_to_string(address, event->address.addr); + + BT_INFO("HID device [%s] disconnected", address); + req_info = __bt_get_request_info(BT_HID_DISCONNECT, address); + if (NULL == req_info) { + BT_DBG("BT_HID_DISCONNECT request not found"); + req_info = __bt_get_request_info(BT_HID_CONNECT, address); + if (NULL == req_info) { + BT_DBG("BT_HID_CONNECT request also not found"); + __bt_handle_hid_disconnection(address); + return; + } else { + /* + * HID_DISCONNECTED event is received in response to hid_connect, + * Set result as BLUETOOTH_ERROR_INTERNAL + * */ + result = BLUETOOTH_ERROR_INTERNAL; + } + } + + if (OAL_STATUS_SUCCESS != event->status) + result = BLUETOOTH_ERROR_INTERNAL; + + if (BLUETOOTH_ERROR_NONE == result) + __bt_handle_hid_disconnection(address); + + if (NULL != req_info) { + out_param = g_array_new(FALSE, FALSE, sizeof(gchar)); + g_array_append_vals(out_param, &device_address, + sizeof(bluetooth_device_address_t)); + _bt_service_method_return(req_info->context, + out_param, result); + g_array_free(out_param, TRUE); + g_free(req_info->user_data); + _bt_free_info_from_invocation_list(req_info); + } + break; + } + case OAL_EVENT_DEVICE_PROPERTIES: { + event_dev_properties_t *event_dev_prop = event_data; + bt_remote_dev_info_t *rem_info; + + BT_INFO("OAL_EVENT_DEVICE_PROPERTIES"); + + rem_info = g_malloc0(sizeof(bt_remote_dev_info_t)); + _bt_copy_remote_dev(rem_info, &event_dev_prop->device_info); + __bt_handle_device_properties(rem_info); + break; + } + default: + BT_ERR("Unhandled event: %d", event_type); + } + + BT_DBG("-"); +} + +int _bt_hidhost_initialize() +{ + BT_DBG("+"); + + /* Enable HID Profile */ + if(OAL_STATUS_SUCCESS != hid_enable()) { + BT_ERR("HID Enable failed"); + return BLUETOOTH_ERROR_INTERNAL; + } + + /* Register HID event handler */ + _bt_service_register_event_handler_callback(BT_HID_MODULE, __bt_hid_event_handler); + return BLUETOOTH_ERROR_NONE; +} + +void _bt_hidhost_deinitialize() +{ + BT_DBG("+"); + + /* Unregister HID event handler */ + _bt_service_unregister_event_handler_callback(BT_HID_MODULE); + + /* Clear connected device list */ + __bt_clear_connected_device_list(); + + /* Disable HID Profile */ + hid_disable(); + + return; +} + +int _bt_hid_connect(bluetooth_device_address_t *device_address) +{ + int result; + char address[BT_ADDRESS_STRING_SIZE]; + bt_address_t bd_addr; + + BT_DBG("+"); + _bt_convert_addr_type_to_string(address, device_address->addr); + BT_INFO("HID connect called for [%s]", address); + + if (TRUE == __bt_is_hid_device_connected(address)) { + BT_ERR("HID device already connected"); + return BLUETOOTH_ERROR_ALREADY_CONNECT; + } + + memset(&bd_addr, 0x00, sizeof(bt_address_t)); + memcpy(bd_addr.addr, device_address->addr, BT_ADDRESS_BYTES_NUM); + + result = hid_connect(&bd_addr); + if (result != OAL_STATUS_SUCCESS) { + BT_ERR("hid_connect error: [%d]", result); + return BLUETOOTH_ERROR_INTERNAL; + } + return BLUETOOTH_ERROR_NONE; +} + +int _bt_hid_disconnect(bluetooth_device_address_t *device_address) +{ + int result; + char address[BT_ADDRESS_STRING_SIZE]; + bt_address_t bd_addr; + + BT_DBG("+"); + _bt_convert_addr_type_to_string(address, device_address->addr); + BT_INFO("HID disconnect called for [%s]", address); + + memset(&bd_addr, 0x00, sizeof(bt_address_t)); + memcpy(bd_addr.addr, device_address->addr, BT_ADDRESS_BYTES_NUM); + + result = hid_disconnect(&bd_addr); + if (result != OAL_STATUS_SUCCESS) { + BT_ERR("hid_disconnect error: [%d]", result); + return BLUETOOTH_ERROR_INTERNAL; + } + return BLUETOOTH_ERROR_NONE; +} diff --git a/bt-service-adaptation/services/include/bt-service-event-receiver.h b/bt-service-adaptation/services/include/bt-service-event-receiver.h index 9e7202c..99e8ce1 100644 --- a/bt-service-adaptation/services/include/bt-service-event-receiver.h +++ b/bt-service-adaptation/services/include/bt-service-event-receiver.h @@ -31,6 +31,7 @@ typedef void (*_bt_service_event_handler_callback) (int event_type, gpointer eve typedef enum { BT_ADAPTER_MODULE, BT_DEVICE_MODULE, + BT_HID_MODULE, } bt_service_module_t; void _bt_service_oal_event_receiver(int event_type, gpointer event_data, gsize len); diff --git a/bt-service-adaptation/services/include/bt-service-hidhost.h b/bt-service-adaptation/services/include/bt-service-hidhost.h new file mode 100644 index 0000000..f4b70c3 --- /dev/null +++ b/bt-service-adaptation/services/include/bt-service-hidhost.h @@ -0,0 +1,41 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Atul Kumar Rai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __BT_SERVICE_HIDHOST_H__ +#define __BT_SERVICE_HIDHOST_H__ + +#include +#include +#include "bluetooth-api.h" + +#ifdef __cplusplus +extern "C" { +#endif + + int _bt_hidhost_initialize(void); + void _bt_hidhost_deinitialize(void); + int _bt_hid_connect(bluetooth_device_address_t *device_address); + int _bt_hid_disconnect(bluetooth_device_address_t *device_address); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __BT_SERVICE_HIDHOST_H__ */ -- 2.7.4