X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-api%2Fbt-hid-device.c;h=e0e8a53623bad77a8343ce2e20255e10289099eb;hb=d3072a95f5ef23bf7749832d5873a5ee200aaffb;hp=2631e1273a2defc93f31d1897073a9e3a397bab2;hpb=bd0758f41be5acaf751d4bd9b89ca63b168fce93;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-api/bt-hid-device.c b/bt-api/bt-hid-device.c index 2631e12..e0e8a53 100644 --- a/bt-api/bt-hid-device.c +++ b/bt-api/bt-hid-device.c @@ -1,11 +1,5 @@ /* - * Bluetooth-frwk - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hocheol Seo - * Girishashok Joshi - * Chanyeol Park + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,43 +26,40 @@ #include "bt-event-handler.h" #define HID_UUID "00001124-0000-1000-8000-00805f9b34fb" +#define HID_DEVICE_UUID "00001124-0000-1000-8000-00805f9b43bf" #define REPORTID_MOUSE 1 #define BT_HID_BUFFER_LEN 100 /* HIDP header masks */ -#define HIDP_HEADER_TRANS_MASK 0xf0 -#define HIDP_HEADER_PARAM_MASK 0x0f +#define BT_HID_HEADER_TRANS_MASK 0xf0 +#define BT_HID_HEADER_PARAM_MASK 0x0f /* HIDP transaction types */ -#define HIDP_TRANS_HANDSHAKE 0x00 -#define HIDP_TRANS_HID_CONTROL 0x10 -#define HIDP_TRANS_GET_REPORT 0x40 -#define HIDP_TRANS_SET_REPORT 0x50 -#define HIDP_TRANS_GET_PROTOCOL 0x60 -#define HIDP_TRANS_SET_PROTOCOL 0x70 -#define HIDP_TRANS_GET_IDLE 0x80 -#define HIDP_TRANS_SET_IDLE 0x90 -#define HIDP_TRANS_DATA 0xa0 -#define HIDP_TRANS_DATC 0xb0 - -#define HIDP_DATA_RTYPE_INPUT 0x01 -#define HIDP_DATA_RTYPE_OUTPUT 0x02 - -#define HIDP_HSHK_SUCCESSFUL 0x00 -#define HIDP_HSHK_NOT_READY 0x01 -#define HIDP_HSHK_ERR_INVALID_REPORT_ID 0x02 -#define HIDP_HSHK_ERR_UNSUPPORTED_REQUEST 0x03 -#define HIDP_HSHK_ERR_INVALID_PARAMETER 0x04 -#define HIDP_HSHK_ERR_UNKNOWN 0x0E -#define HIDP_HSHK_ERR_FATAL 0x0F - -typedef struct { - guint object_id; - gchar *path; - int id; - char *uuid; - GSList *device_list; -} hid_info_t; +#define BT_HID_TRANS_HANDSHAKE 0x00 +#define BT_HID_TRANS_HID_CONTROL 0x10 +#define BT_HID_TRANS_GET_REPORT 0x40 +#define BT_HID_TRANS_SET_REPORT 0x50 +#define BT_HID_TRANS_GET_PROTOCOL 0x60 +#define BT_HID_TRANS_SET_PROTOCOL 0x70 +#define BT_HID_TRANS_GET_IDLE 0x80 +#define BT_HID_TRANS_SET_IDLE 0x90 +#define BT_HID_TRANS_DATA 0xa0 +#define BT_HID_TRANS_DATC 0xb0 + +#define BT_HID_DATA_RTYPE_INPUT 0x01 +#define BT_HID_DATA_RTYPE_OUTPUT 0x02 + +#define BT_HID_HSHK_SUCCESSFUL 0x00 +#define BT_HID_HSHK_NOT_READY 0x01 +#define BT_HID_HSHK_ERR_INVALID_REPORT_ID 0x02 +#define BT_HID_HSHK_ERR_UNSUPPORTED_REQUEST 0x03 +#define BT_HID_HSHK_ERR_INVALID_PARAMETER 0x04 +#define BT_HID_HSHK_ERR_UNKNOWN 0x0E +#define BT_HID_HSHK_ERR_FATAL 0x0F + +#define BT_HID_SERVICE_NAME "org.bluez.hid_agent" +#define BT_HID_AGENT_OBJECT_PATH "/org/bluez/hid_agent" +#define BT_HID_SERVICE_INTERFACE "org.tizen.HidApp" typedef struct { int ctrl_fd; @@ -81,12 +72,12 @@ typedef struct { guint disconnect_idle_id; } hid_connected_device_info_t; -struct reports{ +struct reports { guint8 type; guint8 rep_data[20]; -}__attribute__((__packed__)); +} __attribute__((__packed__)); -static hid_info_t *hid_info = NULL; +static GSList *device_list; /* Variable for privilege, only for write API, before we should reduce time to bt-service dbus calling @@ -98,46 +89,128 @@ static int privilege_token_send_mouse = 0; static int privilege_token_send_key = 0; static int privilege_token_reply = 0; -static gboolean __hid_disconnect(hid_connected_device_info_t *info); +static GVariant* __bt_hid_agent_dbus_send(const char *path, + const char *interface, const char *method, + GError **err, GVariant *parameters) +{ + GVariant *reply = NULL; + GDBusProxy *proxy = NULL; + GDBusConnection *conn = NULL; + + conn = _bt_get_system_private_conn(); + retv_if(conn == NULL, NULL); + + proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, BT_HID_SERVICE_NAME, path, interface, NULL, err); + if (proxy == NULL) { + BT_ERR("Unable to allocate new proxy"); + return NULL; + } + + reply = g_dbus_proxy_call_sync(proxy, method, parameters, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, err); + + g_object_unref(proxy); + return reply; +} static hid_connected_device_info_t *__find_hid_info_with_address(const char *remote_addr) { GSList *l; - for ( l = hid_info->device_list; l != NULL; l = l->next) { + for (l = device_list; l != NULL; l = l->next) { hid_connected_device_info_t *info = l->data; - if (g_strcmp0((const char *)info->address, (const char *)remote_addr) == 0) + if (strcasecmp((const char *)info->address, (const char *)remote_addr) == 0) return info; } return NULL; } static void __hid_connected_cb(hid_connected_device_info_t *info, - bt_event_info_t *event_info) + int result) { - bluetooth_hid_request_t conn_info; + bluetooth_device_address_t bd_addr; + bt_event_info_t *event_info = NULL; + + event_info = _bt_event_get_cb_data(BT_HID_DEVICE_EVENT); + if (event_info == NULL) + return; + + memset(&bd_addr, 0x00, sizeof(bluetooth_device_address_t)); + _bt_convert_addr_string_to_type(bd_addr.addr, info->address); - memset(&conn_info, 0x00, sizeof(bluetooth_hid_request_t)); - if (info->intr_fd != -1 && info->ctrl_fd == -1) - conn_info.socket_fd = info->intr_fd; - else - conn_info.socket_fd = info->ctrl_fd; - _bt_convert_addr_string_to_type (conn_info.device_addr.addr , info->address); + if (result == BLUETOOTH_ERROR_NONE) + BT_INFO_C("Connected [HID Device]"); - BT_INFO_C("Connected [HID Device]"); _bt_common_event_cb(BLUETOOTH_HID_DEVICE_CONNECTED, - BLUETOOTH_ERROR_NONE, &conn_info, + result, &bd_addr, event_info->cb, event_info->user_data); } +static void __hid_connect_response_cb(GDBusProxy *proxy, GAsyncResult *res, + gpointer user_data) + +{ + int result; + GError *error = NULL; + GVariant *ret = NULL; + hid_connected_device_info_t info; + const char *path; + + BT_DBG("+"); + + ret = g_dbus_proxy_call_finish(proxy, res, &error); + if (ret == NULL) { + g_dbus_error_strip_remote_error(error); + BT_ERR("Error : %s \n", error->message); + + info.ctrl_fd = -1; + info.intr_fd = -1; + + info.address = g_malloc0(BT_ADDRESS_STRING_SIZE); + + path = g_dbus_proxy_get_object_path(proxy); + _bt_convert_device_path_to_address(path, info.address); + + if (g_strcmp0(error->message, "Already Connected") == 0) { + bluetooth_device_address_t dev_address = { {0} }; + int ctrl = -1, intr = -1; + + _bt_convert_addr_string_to_type(dev_address.addr, + info.address); + _bt_hid_device_get_fd(info.address, &ctrl, &intr); + if (ctrl != -1 && intr != -1) + _bt_hid_new_connection(&dev_address, ctrl, intr); + else + BT_ERR("fd is invalid.(ctrl=%d, intr=%d)", ctrl, intr); + } else { + if (g_strcmp0(error->message, "In Progress") == 0) + result = BLUETOOTH_ERROR_IN_PROGRESS; + else + result = BLUETOOTH_ERROR_INTERNAL; + + __hid_connected_cb(&info, result); + } + + g_free(info.address); + g_error_free(error); + } else { + g_variant_unref(ret); + } + + if (proxy) + g_object_unref(proxy); + + BT_DBG("-"); +} + static gboolean __hid_disconnect(hid_connected_device_info_t *info) { - bluetooth_hid_request_t disconn_info; - int fd = info->ctrl_fd; + bluetooth_device_address_t bd_addr; bt_event_info_t *event_info; BT_INFO_C("Disconnected [HID Device]"); - hid_info->device_list = g_slist_remove(hid_info->device_list, info); + device_list = g_slist_remove(device_list, info); if (info->ctrl_data_id > 0) { g_source_remove(info->ctrl_data_id); info->ctrl_data_id = 0; @@ -147,13 +220,6 @@ static gboolean __hid_disconnect(hid_connected_device_info_t *info) info->intr_data_id = 0; } - if (info->intr_fd >= 0) { - close(info->ctrl_fd); - close(info->intr_fd); - info->intr_fd = -1; - info->ctrl_fd = -1; - } - if (info->ctrl_data_io) { g_io_channel_shutdown(info->ctrl_data_io, TRUE, NULL); g_io_channel_unref(info->ctrl_data_io); @@ -164,46 +230,33 @@ static gboolean __hid_disconnect(hid_connected_device_info_t *info) g_io_channel_unref(info->intr_data_io); info->intr_data_io = NULL; } + if (info->intr_fd >= 0) { + close(info->ctrl_fd); + close(info->intr_fd); + info->intr_fd = -1; + info->ctrl_fd = -1; + } info->disconnect_idle_id = 0; event_info = _bt_event_get_cb_data(BT_HID_DEVICE_EVENT); - if (event_info == NULL) - return FALSE; + if (event_info != NULL) { + memset(&bd_addr, 0x00, sizeof(bluetooth_device_address_t)); + _bt_convert_addr_string_to_type(bd_addr.addr , info->address); + _bt_common_event_cb(BLUETOOTH_HID_DEVICE_DISCONNECTED, + BLUETOOTH_ERROR_NONE, &bd_addr, + event_info->cb, event_info->user_data); + } - memset(&disconn_info, 0x00, sizeof(bluetooth_hid_request_t)); - disconn_info.socket_fd = fd; - _bt_convert_addr_string_to_type (disconn_info.device_addr.addr , info->address); - _bt_common_event_cb(BLUETOOTH_HID_DEVICE_DISCONNECTED, - BLUETOOTH_ERROR_NONE, &disconn_info, - event_info->cb, event_info->user_data); - if (info->address) - g_free(info->address); + g_free(info->address); g_free(info); - info = NULL; - BT_DBG("-"); + return FALSE; } -void __free_hid_info(hid_info_t *info) +static gboolean __is_error_by_disconnect(GError *err) { - BT_DBG(""); - - _bt_unregister_gdbus(info->object_id); - - while (info->device_list) { - hid_connected_device_info_t *dev_info = NULL; - dev_info = (hid_connected_device_info_t *)info->device_list->data; - - if (dev_info->disconnect_idle_id > 0) { - BT_INFO("Disconnect idle still not process remove source"); - g_source_remove(dev_info->disconnect_idle_id); - dev_info->disconnect_idle_id = 0; - } - __hid_disconnect(dev_info); - } - - g_free(info->path); - g_free(info->uuid); - g_free(info); + return !g_strcmp0(err->message, "Connection reset by peer") || + !g_strcmp0(err->message, "Connection timed out") || + !g_strcmp0(err->message, "Software caused connection abort"); } static gboolean __received_cb(GIOChannel *chan, GIOCondition cond, @@ -211,7 +264,7 @@ static gboolean __received_cb(GIOChannel *chan, GIOCondition cond, { hid_connected_device_info_t *info = data; GIOStatus status = G_IO_STATUS_NORMAL; - char buffer[20]; + char buffer[BT_RFCOMM_BUFFER_LEN]; gsize len = 0; GError *err = NULL; guint8 header, type, param; @@ -220,247 +273,300 @@ static gboolean __received_cb(GIOChannel *chan, GIOCondition cond, if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { BT_ERR_C("HID disconnected: %d", info->ctrl_fd); - if (info->disconnect_idle_id > 0) { - BT_INFO("Disconnect idle still not process remove source"); - g_source_remove(info->disconnect_idle_id); - info->disconnect_idle_id = 0; - } + if (info->disconnect_idle_id > 0) { + BT_INFO("Disconnect idle still not process remove source"); + g_source_remove(info->disconnect_idle_id); + info->disconnect_idle_id = 0; + } __hid_disconnect(info); return FALSE; } + status = g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN, &len, &err); if (status == G_IO_STATUS_NORMAL) { BT_INFO("Parsing Data"); - bluetooth_hid_received_data_t data = {0}; + bluetooth_hid_received_data_t recv_data = {0}; header = buffer[0]; - type = header & HIDP_HEADER_TRANS_MASK; - param = header & HIDP_HEADER_PARAM_MASK; + type = header & BT_HID_HEADER_TRANS_MASK; + param = header & BT_HID_HEADER_PARAM_MASK; BT_INFO("type %d , param %d", type, param); BT_INFO("Data Reveived from %s" , info->address); - data.address = g_strdup(info->address); + + event_info = _bt_event_get_cb_data(BT_HID_DEVICE_EVENT); + if (event_info == NULL) + return FALSE; + + recv_data.address = g_strdup(info->address); switch (type) { - case HIDP_TRANS_HANDSHAKE: - BT_INFO("TRANS HANDSHAKE"); - data.type = HTYPE_TRANS_HANDSHAKE; - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - break; - case HIDP_TRANS_HID_CONTROL: - BT_INFO("HID CONTROL"); - data.type = HTYPE_TRANS_HID_CONTROL; - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - break; - case HIDP_TRANS_DATA: - BT_INFO("TRANS DATA"); - data.type = HTYPE_TRANS_DATA; - if ( param & HIDP_DATA_RTYPE_INPUT) { - BT_INFO("Input Report"); - data.param = PTYPE_DATA_RTYPE_INPUT; - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - } - else { - BT_INFO("Out Report"); - data.param = PTYPE_DATA_RTYPE_OUTPUT; - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - } - break; - case HIDP_TRANS_GET_REPORT: { - BT_INFO("Get Report"); - data.type = HTYPE_TRANS_GET_REPORT; - if (param & HIDP_DATA_RTYPE_INPUT) { - BT_INFO("Input Report"); - data.param = PTYPE_DATA_RTYPE_INPUT; - } else { - BT_INFO("Output Report"); - data.param = PTYPE_DATA_RTYPE_OUTPUT; - } - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - break; - } - case HIDP_TRANS_SET_REPORT: { - BT_INFO("Set Report"); - data.type = HTYPE_TRANS_SET_REPORT; - if (param & HIDP_DATA_RTYPE_INPUT) { - BT_INFO("Input Report"); - data.param = PTYPE_DATA_RTYPE_INPUT; - } else { - BT_INFO("Output Report"); - data.param = PTYPE_DATA_RTYPE_OUTPUT; - } - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - break; - } - case HIDP_TRANS_GET_PROTOCOL:{ - BT_INFO("Get_PROTOCOL"); - data.type = HTYPE_TRANS_GET_PROTOCOL; - data.param = PTYPE_DATA_RTYPE_INPUT; - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - break; + case BT_HID_TRANS_HANDSHAKE: + BT_INFO("TRANS HANDSHAKE"); + recv_data.type = HTYPE_TRANS_HANDSHAKE; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + + case BT_HID_TRANS_HID_CONTROL: + BT_INFO("HID CONTROL"); + recv_data.type = HTYPE_TRANS_HID_CONTROL; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + + case BT_HID_TRANS_DATA: + BT_INFO("TRANS DATA"); + recv_data.type = HTYPE_TRANS_DATA; + if (param & BT_HID_DATA_RTYPE_INPUT) { + BT_INFO("Input Report"); + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + } else { + BT_INFO("Out Report"); + recv_data.param = PTYPE_DATA_RTYPE_OUTPUT; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); } - case HIDP_TRANS_SET_PROTOCOL:{ - BT_INFO("Set_PROTOCOL"); - data.type = HTYPE_TRANS_SET_PROTOCOL; - data.param = PTYPE_DATA_RTYPE_INPUT; - data.buffer_size = len; - data.buffer = (char *) malloc(sizeof(char) * len); - /* Fix : NULL_RETURNS */ - if (NULL == data.buffer) { - BT_ERR("Failed to allocate memory"); - data.buffer_size = 0; - } else { - memcpy(data.buffer, buffer, len); - } - break; + break; + + case BT_HID_TRANS_GET_REPORT: { + BT_INFO("Get Report"); + recv_data.type = HTYPE_TRANS_GET_REPORT; + if (param & BT_HID_DATA_RTYPE_INPUT) { + BT_INFO("Input Report"); + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + } else { + BT_INFO("Output Report"); + recv_data.param = PTYPE_DATA_RTYPE_OUTPUT; } - default: { - BT_INFO("unsupported HIDP control message"); - BT_ERR("Send Handshake Message"); - guint8 type = HIDP_TRANS_HANDSHAKE | - HIDP_HSHK_ERR_UNSUPPORTED_REQUEST; - data.type = HTYPE_TRANS_UNKNOWN; - int fd = g_io_channel_unix_get_fd(chan); - int bytes = write(fd, &type, sizeof(type)); - BT_INFO("Bytes Written %d", bytes); - break; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + } + + case BT_HID_TRANS_SET_REPORT: { + BT_INFO("Set Report"); + recv_data.type = HTYPE_TRANS_SET_REPORT; + if (param & BT_HID_DATA_RTYPE_INPUT) { + BT_INFO("Input Report"); + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + } else { + BT_INFO("Output Report"); + recv_data.param = PTYPE_DATA_RTYPE_OUTPUT; } + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + } + + case BT_HID_TRANS_GET_PROTOCOL:{ + BT_INFO("Get_PROTOCOL"); + recv_data.type = HTYPE_TRANS_GET_PROTOCOL; + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + } + + case BT_HID_TRANS_SET_PROTOCOL:{ + BT_INFO("Set_PROTOCOL"); + recv_data.type = HTYPE_TRANS_SET_PROTOCOL; + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; } - event_info = _bt_event_get_cb_data(BT_HID_DEVICE_EVENT); - if (event_info == NULL) - return FALSE; - _bt_common_event_cb(BLUETOOTH_HID_DEVICE_DATA_RECEIVED, - BLUETOOTH_ERROR_NONE, &data, + case BT_HID_TRANS_GET_IDLE:{ + BT_INFO("Get_IDLE"); + recv_data.type = HTYPE_TRANS_GET_IDLE; + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + } + + case BT_HID_TRANS_SET_IDLE:{ + BT_INFO("Set_IDLE"); + recv_data.type = HTYPE_TRANS_SET_IDLE; + recv_data.param = PTYPE_DATA_RTYPE_INPUT; + recv_data.buffer_size = len; + recv_data.buffer = (char *)g_malloc0(sizeof(char) * len); + memcpy(recv_data.buffer, buffer, len); + break; + } + + default: { + BT_INFO("unsupported HIDP control message"); + BT_ERR("Send Handshake Message"); + guint8 type = BT_HID_TRANS_HANDSHAKE | + BT_HID_HSHK_ERR_UNSUPPORTED_REQUEST; + recv_data.type = HTYPE_TRANS_UNKNOWN; + int fd = g_io_channel_unix_get_fd(chan); + int bytes = write(fd, &type, sizeof(type)); + BT_INFO("Bytes Written %d", bytes); + break; + } + } + + _bt_common_event_cb(BLUETOOTH_HID_DEVICE_DATA_RECEIVED, + BLUETOOTH_ERROR_NONE, &recv_data, event_info->cb, event_info->user_data); - if (data.buffer) - g_free(data.buffer); - if (data.address) - g_free((char *)data.address); + if (recv_data.buffer) + g_free(recv_data.buffer); + + if (recv_data.address) + g_free((char *)recv_data.address); } else { - BT_INFO("Error while reading data"); + BT_ERR("Error while reading data %d [%s]", status, info->address); + if (err) { + BT_ERR("IO Channel read error [%s]", err->message); + if (status == G_IO_STATUS_ERROR && + __is_error_by_disconnect(err)) { + BT_DBG("cond : %d", cond); + g_error_free(err); + __hid_disconnect(info); + return FALSE; + } + g_error_free(err); + } else if (status == G_IO_STATUS_EOF) { + __hid_disconnect(info); + return FALSE; + } } return TRUE; } -int new_hid_connection(const char *path, int fd, bluetooth_device_address_t *addr) +static void __free_hid_info(void *data) +{ + BT_DBG(""); + + hid_connected_device_info_t *dev_info = (hid_connected_device_info_t *)data; + + if (dev_info->disconnect_idle_id > 0) { + BT_INFO("Disconnect idle still not process remove source"); + g_source_remove(dev_info->disconnect_idle_id); + dev_info->disconnect_idle_id = 0; + } + __hid_disconnect(dev_info); +} + +int _bt_hid_device_get_fd(const char *address, int *ctrl, int *intr) +{ + + int ret = BLUETOOTH_ERROR_NONE; + char *adapter_path; + GVariant *result = NULL; + GError *err = NULL; + GDBusConnection *conn; + GDBusProxy *server_proxy; + int index1 = 0; + int index2 = 0; + GUnixFDList *out_fd_list = NULL; + conn = _bt_get_system_private_conn(); + retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); + + adapter_path = _bt_get_device_object_path((char *)address); + retv_if(adapter_path == NULL, BLUETOOTH_ERROR_INTERNAL); + BT_INFO_C("Device : %s", adapter_path); + server_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, BT_BLUEZ_NAME, + adapter_path, "org.bluez.Input1", NULL, NULL); + g_free(adapter_path); + + if (server_proxy == NULL) { + BT_ERR("Failed to get the network server proxy\n"); + return BLUETOOTH_ERROR_INTERNAL; + } + + result = g_dbus_proxy_call_with_unix_fd_list_sync(server_proxy, "GetFD", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &out_fd_list, + NULL, + &err); + if (result == NULL) { + if (err != NULL) { + g_dbus_error_strip_remote_error(err); + BT_ERR("INPUT server register Error: %s\n", err->message); + if (g_strcmp0(err->message, "Already Exists") == 0) + ret = BLUETOOTH_ERROR_ALREADY_INITIALIZED; + else + ret = BLUETOOTH_ERROR_INTERNAL; + + g_error_free(err); + } + } else { + g_variant_get(result, "(hh)", &index1, &index2); + int fd1 = g_unix_fd_list_get(out_fd_list, index1, NULL); + int fd2 = g_unix_fd_list_get(out_fd_list, index2, NULL); + + *ctrl = fd1; + *intr = fd2; + g_object_unref(out_fd_list); + g_variant_unref(result); + } + g_object_unref(server_proxy); + return ret; +} + +int _bt_hid_new_connection(bluetooth_device_address_t *addr, + int ctrl_fd, int intr_fd) { - hid_info_t *info = NULL; hid_connected_device_info_t *dev_info = NULL; - bt_event_info_t *event_info = NULL; char address[18]; - info = hid_info; + char secure_addr[BT_ADDRESS_STRING_SIZE] = { 0 }; - if (info == NULL) - return -1; _bt_convert_addr_type_to_string((char *)address, addr->addr); - BT_INFO("Address [%s]", address); + _bt_convert_addr_string_to_secure_string(secure_addr, address); + BT_INFO("Address [%s]", secure_addr); dev_info = __find_hid_info_with_address(address); - if (dev_info == NULL) { - dev_info = (hid_connected_device_info_t *) - g_malloc0(sizeof(hid_connected_device_info_t)); - dev_info->intr_fd = -1; - dev_info->ctrl_fd = -1; - dev_info->intr_fd = fd; - dev_info->address = g_strdup(address); - dev_info->intr_data_io = g_io_channel_unix_new(dev_info->intr_fd); - g_io_channel_set_encoding(dev_info->intr_data_io, NULL, NULL); - g_io_channel_set_flags(dev_info->intr_data_io, G_IO_FLAG_NONBLOCK, NULL); - - dev_info->intr_data_id = g_io_add_watch(dev_info->intr_data_io, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - __received_cb, dev_info); - hid_info->device_list = g_slist_append(hid_info->device_list, dev_info); - } else { - dev_info->ctrl_fd = fd; - dev_info->ctrl_data_io = g_io_channel_unix_new(dev_info->ctrl_fd); - g_io_channel_set_encoding(dev_info->ctrl_data_io, NULL, NULL); - g_io_channel_set_flags(dev_info->ctrl_data_io, G_IO_FLAG_NONBLOCK, NULL); - - dev_info->ctrl_data_id = g_io_add_watch(dev_info->ctrl_data_io, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - __received_cb, dev_info); - } - if (dev_info->ctrl_fd != -1 && dev_info->intr_fd != -1) { - event_info = _bt_event_get_cb_data(BT_HID_DEVICE_EVENT); - if (event_info) - __hid_connected_cb(dev_info, event_info); - } + if (dev_info != NULL) + __free_hid_info(dev_info); + + dev_info = (hid_connected_device_info_t *) + g_malloc0(sizeof(hid_connected_device_info_t)); + + dev_info->ctrl_fd = ctrl_fd; + dev_info->intr_fd = intr_fd; + dev_info->address = g_strdup(address); + dev_info->ctrl_data_io = g_io_channel_unix_new(dev_info->ctrl_fd); + dev_info->intr_data_io = g_io_channel_unix_new(dev_info->intr_fd); + g_io_channel_set_encoding(dev_info->ctrl_data_io, NULL, NULL); + g_io_channel_set_flags(dev_info->ctrl_data_io, G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref(dev_info->ctrl_data_io, TRUE); + g_io_channel_set_encoding(dev_info->intr_data_io, NULL, NULL); + g_io_channel_set_flags(dev_info->intr_data_io, G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref(dev_info->intr_data_io, TRUE); + dev_info->ctrl_data_id = g_io_add_watch(dev_info->ctrl_data_io, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + __received_cb, dev_info); + dev_info->intr_data_id = g_io_add_watch(dev_info->intr_data_io, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + __received_cb, dev_info); + device_list = g_slist_append(device_list, dev_info); + + __hid_connected_cb(dev_info, BLUETOOTH_ERROR_NONE); return 0; } -static hid_info_t *__register_method() -{ - int object_id; - hid_info_t *info = NULL; - char *path = NULL; - path = g_strdup_printf("/org/socket/server/%d", getpid()); - object_id = _bt_register_new_conn(path, new_hid_connection); - if (object_id < 0) { - return NULL; - } - info = g_new(hid_info_t, 1); - info->object_id = (guint)object_id; - info->path = path; - info->id = 0; - info->device_list = NULL; +void _bt_hid_free_hid_info(void) +{ + g_slist_free_full(device_list, __free_hid_info); - return info; + device_list = NULL; } BT_EXPORT_API int bluetooth_hid_device_init(hid_cb_func_ptr callback_ptr, void *user_data) @@ -500,8 +606,10 @@ BT_EXPORT_API int bluetooth_hid_device_deinit(void) BT_EXPORT_API int bluetooth_hid_device_activate(void) { - bt_register_profile_info_t profile_info; - int result = BLUETOOTH_ERROR_NONE; + GVariant *reply; + GError *err = NULL; + + BT_CHECK_ENABLED(return); if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_ACTIVATE) == BLUETOOTH_ERROR_PERMISSION_DEINED) { @@ -509,43 +617,64 @@ BT_EXPORT_API int bluetooth_hid_device_activate(void) return BLUETOOTH_ERROR_PERMISSION_DEINED; } - if (hid_info != NULL) - return BLUETOOTH_ERROR_IN_PROGRESS; - - hid_info = __register_method(); - if (hid_info == NULL) - return BLUETOOTH_ERROR_INTERNAL; - - hid_info->uuid = g_strdup(HID_UUID); - - profile_info.authentication = TRUE; - profile_info.authorization = TRUE; - profile_info.obj_path = hid_info->path; - profile_info.role = g_strdup("Hid"); - profile_info.service = hid_info->uuid; - profile_info.uuid = hid_info->uuid; + reply = __bt_hid_agent_dbus_send(BT_HID_AGENT_OBJECT_PATH, + BT_HID_SERVICE_INTERFACE, + "RegisterApplication", &err, NULL); + + if (!reply) { + int ret = BLUETOOTH_ERROR_INTERNAL; + BT_ERR("Error returned in method call"); + if (err) { + BT_ERR("Error = %s", err->message); + if (strcmp(err->message, BT_ERROR_ALREADY_EXIST) == 0) + ret = BLUETOOTH_ERROR_IN_PROGRESS; + else + ret = BLUETOOTH_ERROR_INTERNAL; + g_clear_error(&err); + } + return ret; + } - BT_INFO("uuid %s", profile_info.uuid); - result = _bt_register_profile_platform(&profile_info, FALSE); + g_variant_unref(reply); - return result; + return BLUETOOTH_ERROR_NONE; } BT_EXPORT_API int bluetooth_hid_device_deactivate(void) { + GVariant *reply; + GError *err = NULL; + + BT_CHECK_ENABLED(return); + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_DEACTIVATE) == BLUETOOTH_ERROR_PERMISSION_DEINED) { BT_ERR("Don't have a privilege to use this API"); return BLUETOOTH_ERROR_PERMISSION_DEINED; } - if (hid_info == NULL) - return BLUETOOTH_ERROR_NOT_IN_OPERATION; + reply = __bt_hid_agent_dbus_send(BT_HID_AGENT_OBJECT_PATH, + BT_HID_SERVICE_INTERFACE, + "UnregisterApplication", &err, NULL); + + if (!reply) { + int ret = BLUETOOTH_ERROR_INTERNAL; + BT_ERR("Error returned in method call"); + if (err) { + BT_ERR("Error = %s", err->message); + if (strcmp(err->message, BT_ERROR_NOT_AVAILABLE) == 0) + ret = BLUETOOTH_ERROR_NOT_IN_OPERATION; + else + ret = BLUETOOTH_ERROR_INTERNAL; + g_clear_error(&err); + } + return ret; + } + + g_variant_unref(reply); - _bt_unregister_profile(hid_info->path); + _bt_hid_free_hid_info(); - __free_hid_info(hid_info); - hid_info = NULL; return BLUETOOTH_ERROR_NONE; } @@ -553,9 +682,12 @@ BT_EXPORT_API int bluetooth_hid_device_connect(const char *remote_addr) { char device_address[BT_ADDRESS_STRING_SIZE] = {0}; hid_connected_device_info_t *info = NULL; + int ret; BT_DBG("+"); BT_CHECK_PARAMETER(remote_addr, return); + BT_CHECK_ENABLED(return); + info = __find_hid_info_with_address(remote_addr); if (info) { BT_ERR("Connection Already Exists"); @@ -568,24 +700,30 @@ BT_EXPORT_API int bluetooth_hid_device_connect(const char *remote_addr) } memcpy(device_address, remote_addr, BT_ADDRESS_STRING_SIZE); - _bt_connect_profile(device_address, HID_UUID, NULL, NULL); + ret = _bt_connect_profile(device_address, HID_DEVICE_UUID, + __hid_connect_response_cb, NULL); - return BLUETOOTH_ERROR_NONE; + return ret; } BT_EXPORT_API int bluetooth_hid_device_disconnect(const char *remote_addr) { + BT_CHECK_PARAMETER(remote_addr, return); + + BT_CHECK_ENABLED(return); + if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_DISCONNECT) == BLUETOOTH_ERROR_PERMISSION_DEINED) { BT_ERR("Don't have a privilege to use this API"); return BLUETOOTH_ERROR_PERMISSION_DEINED; } + hid_connected_device_info_t *info = NULL; info = __find_hid_info_with_address(remote_addr); if (info == NULL) return BLUETOOTH_ERROR_INVALID_PARAM; - _bt_disconnect_profile((char *)remote_addr, HID_UUID, NULL, NULL); + _bt_disconnect_profile((char *)remote_addr, HID_DEVICE_UUID, NULL, NULL); info->disconnect_idle_id = g_idle_add((GSourceFunc)__hid_disconnect, info); @@ -599,9 +737,11 @@ BT_EXPORT_API int bluetooth_hid_device_send_mouse_event(const char *remote_addr, int written = 0; hid_connected_device_info_t *info = NULL; + BT_CHECK_PARAMETER(remote_addr, return); + switch (privilege_token_send_mouse) { case 0: - result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HID_DEVICE_SEND_MOUSE_EVENT); + result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_SEND_MOUSE_EVENT); if (result == BLUETOOTH_ERROR_NONE) { privilege_token_send_mouse = 1; /* Have a permission */ @@ -627,17 +767,14 @@ BT_EXPORT_API int bluetooth_hid_device_send_mouse_event(const char *remote_addr, BT_ERR("Connection Information not found"); return BLUETOOTH_ERROR_INVALID_PARAM; } - int socket_fd; - if (info == NULL) - return -1; - - if (info->intr_fd != -1 && info->ctrl_fd == -1) - socket_fd = info->intr_fd; - else - socket_fd = info->ctrl_fd; - - written = write(socket_fd, &send_event, sizeof(send_event)); + if (info->intr_fd >= 0) { + written = write(info->intr_fd, &send_event, sizeof(send_event)); + } else { + BT_ERR("intr_fd(%d) is invalid.", info->intr_fd); + __free_hid_info(info); + return BLUETOOTH_ERROR_INTERNAL; + } return written; } @@ -649,9 +786,11 @@ BT_EXPORT_API int bluetooth_hid_device_send_key_event(const char *remote_addr, int written = 0; hid_connected_device_info_t *info = NULL; + BT_CHECK_PARAMETER(remote_addr, return); + switch (privilege_token_send_key) { case 0: - result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HID_DEVICE_SEND_KEY_EVENT); + result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_SEND_KEY_EVENT); if (result == BLUETOOTH_ERROR_NONE) { privilege_token_send_key = 1; /* Have a permission */ @@ -679,17 +818,74 @@ BT_EXPORT_API int bluetooth_hid_device_send_key_event(const char *remote_addr, return BLUETOOTH_ERROR_INVALID_PARAM; } - int socket_fd; + if (info->intr_fd >= 0) { + written = write(info->intr_fd, &send_event, sizeof(send_event)); + } else { + BT_ERR("intr_fd(%d) is invalid.", info->intr_fd); + __free_hid_info(info); + return BLUETOOTH_ERROR_INTERNAL; + } + + return written; +} - if (info == NULL) - return -1; +BT_EXPORT_API int bluetooth_hid_device_send_custom_event(const char *remote_addr, + unsigned char btcode, unsigned char report_id, + const char *data, unsigned int data_len) +{ + int result; + int written = 0; + hid_connected_device_info_t *info = NULL; + char *send_event = NULL; + + BT_CHECK_PARAMETER(remote_addr, return); + BT_CHECK_PARAMETER(data, return); - if (info->intr_fd != -1 && info->ctrl_fd == -1) - socket_fd = info->intr_fd; - else - socket_fd = info->ctrl_fd; + switch (privilege_token_send_key) { + case 0: + result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_SEND_CUSTOM_EVENT); + + if (result == BLUETOOTH_ERROR_NONE) { + privilege_token_send_key = 1; /* Have a permission */ + } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) { + BT_ERR("Don't have a privilege to use this API"); + privilege_token_send_key = -1; /* Don't have a permission */ + return BLUETOOTH_ERROR_PERMISSION_DEINED; + } else { + /* Just break - It is not related with permission error */ + } + break; + case 1: + /* Already have a privilege */ + break; + case -1: + return BLUETOOTH_ERROR_PERMISSION_DEINED; + default: + /* Invalid privilge token value */ + return BLUETOOTH_ERROR_INTERNAL; + } + + info = __find_hid_info_with_address(remote_addr); + if (info == NULL) { + BT_ERR("Connection Information not found"); + return BLUETOOTH_ERROR_INVALID_PARAM; + } + + if (info->intr_fd >= 0) { + send_event = g_malloc0(data_len + 2); + + send_event[0] = (char)btcode; + send_event[1] = (char)report_id; + memcpy(send_event + 2, data, data_len); + + written = write(info->intr_fd, send_event, data_len + 2); + g_free(send_event); + } else { + BT_ERR("intr_fd(%d) is invalid.", info->intr_fd); + __free_hid_info(info); + return BLUETOOTH_ERROR_INTERNAL; + } - written = write(socket_fd, &send_event, sizeof(send_event)); return written; } @@ -701,17 +897,26 @@ BT_EXPORT_API int bluetooth_hid_device_reply_to_report(const char *remote_addr, { int result; struct reports output_report = { 0 }; - int bytes = 0; + int bytes = -1; hid_connected_device_info_t *info = NULL; + + BT_CHECK_PARAMETER(remote_addr, return); + info = __find_hid_info_with_address(remote_addr); if (info == NULL) { BT_ERR("Connection Information not found"); return BLUETOOTH_ERROR_INVALID_PARAM; } + if (info->ctrl_fd < 0) { + BT_ERR("ctrl_fd(%d) is invalid.", info->ctrl_fd); + __free_hid_info(info); + return BLUETOOTH_ERROR_INTERNAL; + } + switch (privilege_token_reply) { case 0: - result = _bt_check_privilege(BT_BLUEZ_SERVICE, BT_HID_DEVICE_SEND_REPLY_TO_REPORT); + result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_HID_DEVICE_SEND_REPLY_TO_REPORT); if (result == BLUETOOTH_ERROR_NONE) { privilege_token_reply = 1; /* Have a permission */ @@ -734,52 +939,68 @@ BT_EXPORT_API int bluetooth_hid_device_reply_to_report(const char *remote_addr, } BT_INFO("htype %d ptype %d", htype, ptype); - switch(htype) { - case HTYPE_TRANS_GET_REPORT: { - switch(ptype) { - case PTYPE_DATA_RTYPE_INPUT: { - output_report.type = HIDP_TRANS_DATA | - HIDP_DATA_RTYPE_INPUT; - memcpy(output_report.rep_data, data, data_len); - bytes = write(info->intr_fd, &output_report, - sizeof(output_report)); - BT_DBG("Bytes Written %d", bytes); - break; - } - default: - BT_INFO("Not Supported"); - break; - } - break; - case HTYPE_TRANS_GET_PROTOCOL: { - BT_DBG("Replying to Get_PROTOCOL"); - output_report.type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUTPUT; - output_report.rep_data[0] = data[0]; - bytes = write(info->intr_fd, &output_report, 2); - BT_DBG("Bytes Written %d", bytes); - break; - } - case HTYPE_TRANS_SET_PROTOCOL: { - BT_DBG("Reply to Set_Protocol"); - output_report.type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT; + switch (htype) { + case HTYPE_TRANS_GET_REPORT: { + switch (ptype) { + case PTYPE_DATA_RTYPE_INPUT: { + output_report.type = BT_HID_TRANS_DATA | + BT_HID_DATA_RTYPE_INPUT; memcpy(output_report.rep_data, data, data_len); bytes = write(info->ctrl_fd, &output_report, - sizeof(output_report)); + sizeof(output_report)); BT_DBG("Bytes Written %d", bytes); break; } - case HTYPE_TRANS_HANDSHAKE: { - BT_DBG("Replying Handshake"); - output_report.type = HIDP_TRANS_HANDSHAKE | data[0]; - memset(output_report.rep_data, 0, sizeof(output_report.rep_data)); - bytes = write(info->intr_fd, &output_report.type, - sizeof(output_report.type)); - BT_DBG("Bytes Written %d", bytes); + default: + BT_INFO("Not Supported"); break; - } - default: - break; + } + break; + + case HTYPE_TRANS_GET_PROTOCOL: { + output_report.type = BT_HID_TRANS_DATA | BT_HID_DATA_RTYPE_OUTPUT; + output_report.rep_data[0] = data[0]; + bytes = write(info->ctrl_fd, &output_report, 2); + break; + } + + case HTYPE_TRANS_SET_PROTOCOL: { + output_report.type = BT_HID_TRANS_DATA | BT_HID_DATA_RTYPE_INPUT; + memcpy(output_report.rep_data, data, data_len); + bytes = write(info->ctrl_fd, &output_report, + sizeof(output_report)); + break; + } + + case HTYPE_TRANS_HANDSHAKE: { + output_report.type = BT_HID_TRANS_HANDSHAKE | data[0]; + memset(output_report.rep_data, 0, sizeof(output_report.rep_data)); + bytes = write(info->ctrl_fd, &output_report.type, + sizeof(output_report.type)); + break; + } + + case HTYPE_TRANS_GET_IDLE: { + output_report.type = BT_HID_TRANS_DATA | BT_HID_DATA_RTYPE_OUTPUT; + output_report.rep_data[0] = data[0]; + bytes = write(info->ctrl_fd, &output_report, 2); + break; + } + + case HTYPE_TRANS_SET_IDLE: { + output_report.type = BT_HID_TRANS_DATA | BT_HID_DATA_RTYPE_INPUT; + memcpy(output_report.rep_data, data, data_len); + bytes = write(info->ctrl_fd, &output_report, + sizeof(output_report)); + break; + } + + default: + break; } } + + BT_DBG("Bytes Written %d", bytes); + return bytes; }