acea5b7d546bd50175e87bac92e589d9820283c5
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / hid / bt-service-hidhost.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Atul Kumar Rai <a.rai@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <glib.h>
24 #include <gio/gio.h>
25 #include <dlog.h>
26 #include <string.h>
27
28 #include "bt-internal-types.h"
29 #include "bt-request-handler.h"
30 #include "bt-service-util.h"
31 #include "bt-service-event.h"
32 #include "bt-service-event-receiver.h"
33 #include "bt-service-common.h"
34 #include "bt-service-hidhost.h"
35 #include "bt-service-core-device.h"
36 #include "oal-event.h"
37 #include "oal-device-mgr.h"
38 #include "oal-hid-host.h"
39
40 typedef struct {
41         char address[BT_ADDRESS_STRING_SIZE];
42         unsigned char num_retries;
43 } bt_hid_wait_data_t;
44
45 static GSList *g_connected_list;
46
47 static gboolean __bt_is_hid_device_connected(const char *address)
48 {
49         GSList *node;
50
51         BT_DBG("+");
52
53         node = g_connected_list;
54         while (node != NULL) {
55                 char *addr_str = node->data;
56
57                 if (g_strcmp0(addr_str, address) == 0) {
58                         BT_ERR("Device present in the list");
59                         return TRUE;
60                 }
61                 node = g_slist_next(node);
62         }
63
64         BT_DBG("-");
65         return FALSE;
66 }
67
68 static void __bt_add_hid_device_to_connected_list(const char *address)
69 {
70         char *addr_str;
71
72         BT_DBG("+");
73
74         if (TRUE == __bt_is_hid_device_connected(address)) {
75                 BT_ERR("Device already present in the list");
76                 return;
77         }
78
79         addr_str = g_strdup(address);
80         g_connected_list = g_slist_append(g_connected_list, addr_str);
81         BT_DBG("-");
82 }
83
84 static void __bt_remove_hid_device_from_connected_list(const char *address)
85 {
86         GSList *node;
87
88         BT_DBG("+");
89
90         node = g_connected_list;
91         while (node != NULL) {
92                 char *addr_str = node->data;
93                 if (g_strcmp0(addr_str, address) == 0) {
94                         BT_DBG("Address match");
95                         g_connected_list = g_slist_remove(g_connected_list, addr_str);
96                         g_free(addr_str);
97                         break;
98                 }
99
100                 node = g_slist_next(node);
101         }
102
103         BT_DBG("-");
104 }
105
106 static void __bt_send_hid_connected(const char *address)
107 {
108         int result = BLUETOOTH_ERROR_NONE;
109         GVariant *param;
110
111         BT_DBG("+");
112
113         if (!__bt_is_hid_device_connected(address)) {
114                 BT_ERR("HID device [%s] not connected anymore", address);
115                 return;
116         }
117
118         /* Send HID connected event to Application */
119         param = g_variant_new("(is)", result, address);
120         _bt_send_event(BT_HID_EVENT, BLUETOOTH_HID_CONNECTED, param);
121         BT_PERMANENT_LOG("Connected HID Host");
122
123         BT_DBG("-");
124 }
125
126 static gboolean __hid_get_bonded_info(gpointer data)
127 {
128         bt_hid_wait_data_t *wait_data = data;
129
130         BT_DBG("+");
131         if ((wait_data->num_retries > 0) && !_bt_is_bonded_devices_retrived()) {
132                 wait_data->num_retries--;
133                 return TRUE;
134         }
135
136         if (wait_data->num_retries <= 0) {
137                 BT_ERR_C("Even after all retries, bonded devices stil not retrieved");
138                 goto done;
139         }
140
141         BT_DBG("bonded info retrival completed, try to get device info");
142         if (NULL == _bt_service_get_remote_dev_info(wait_data->address)) {
143                 BT_ERR_C("Unexpected: _bt_service_get_remote_dev_info() returned NULL");
144                 goto done;
145         }
146
147         __bt_send_hid_connected(wait_data->address);
148
149 done:
150         g_free(wait_data);
151         BT_DBG("-");
152         return FALSE;
153 }
154
155 static void __bt_handle_hid_connection(char *address)
156 {
157         BT_DBG("+");
158
159         ret_if(NULL == address);
160         __bt_add_hid_device_to_connected_list(address);
161
162         if (!_bt_is_bonded_devices_retrived()) {
163                 /* Wait till bonded devices retrival is completed */
164                 bt_hid_wait_data_t *wait_data = g_malloc0(sizeof(bt_hid_wait_data_t));
165                 g_strlcpy(wait_data->address, address, BT_ADDRESS_STRING_SIZE);
166                 wait_data->num_retries = 5;
167                 g_timeout_add_seconds(1, __hid_get_bonded_info, (gpointer)wait_data);
168                 return;
169         }
170
171         __bt_send_hid_connected(address);
172         BT_DBG("-");
173 }
174
175 static void __bt_handle_hid_disconnection(char *address)
176 {
177         int result = BLUETOOTH_ERROR_NONE;
178         GVariant *param;
179
180         BT_DBG("+");
181
182         ret_if(NULL == address);
183
184         /* Remove HID device from connected list */
185         __bt_remove_hid_device_from_connected_list(address);
186
187         /* Send HID disconnected event to Application */
188         param = g_variant_new("(is)", result, address);
189         _bt_send_event(BT_HID_EVENT, BLUETOOTH_HID_DISCONNECTED, param);
190         BT_PERMANENT_LOG("Disconnected HID Host");
191
192         BT_DBG("-");
193 }
194
195 static void __bt_hid_event_handler(int event_type, gpointer event_data)
196 {
197         bluetooth_device_address_t device_address;
198         char address[BT_ADDRESS_STRING_SIZE];
199
200         int result = BLUETOOTH_ERROR_NONE;
201
202         invocation_info_t *req_info;
203         GArray *out_param;
204
205         BT_DBG("+");
206
207         switch (event_type) {
208         case OAL_EVENT_HID_CONNECTED: {
209                 event_hid_conn_t *event = event_data;
210
211                 memset(&device_address, 0x00, sizeof(bluetooth_device_address_t));
212                 memcpy(device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
213
214                 memset(address, 0x00, BT_ADDRESS_STRING_SIZE);
215                 _bt_convert_addr_type_to_string(address, event->address.addr);
216
217                 /* Reply to async request for HID connect, if any */
218                 req_info = _bt_get_request_info_data(BT_HID_CONNECT, address);
219                 if (NULL != req_info) {
220                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
221                         g_array_append_vals(out_param, &device_address,
222                                         sizeof(bluetooth_device_address_t));
223                         _bt_service_method_return(req_info->context,
224                                         out_param, result);
225                         g_array_free(out_param, TRUE);
226                         _bt_free_info_from_invocation_list(req_info);
227                 }
228                 __bt_handle_hid_connection(address);
229                 break;
230         }
231         case OAL_EVENT_HID_DISCONNECTED: {
232                 event_hid_conn_t *event = event_data;
233
234                 memset(&device_address, 0x00, sizeof(bluetooth_device_address_t));
235                 memcpy(device_address.addr, event->address.addr, BLUETOOTH_ADDRESS_LENGTH);
236
237                 memset(address, 0x00, BT_ADDRESS_STRING_SIZE);
238                 _bt_convert_addr_type_to_string(address, event->address.addr);
239
240                 BT_INFO("HID device [%s] disconnected", address);
241                 req_info = _bt_get_request_info_data(BT_HID_DISCONNECT, address);
242                 if (NULL == req_info) {
243                         BT_DBG("BT_HID_DISCONNECT request not found");
244                         req_info = _bt_get_request_info_data(BT_HID_CONNECT, address);
245                         if (NULL == req_info) {
246                                 BT_DBG("BT_HID_CONNECT request also not found");
247                                 __bt_handle_hid_disconnection(address);
248                                 return;
249                         } else {
250                                 /*
251                                  * HID_DISCONNECTED event is received in response to hid_connect,
252                                  * Set result as BLUETOOTH_ERROR_INTERNAL
253                                  */
254                                 result = BLUETOOTH_ERROR_INTERNAL;
255                         }
256                 }
257
258                 if (OAL_STATUS_SUCCESS != event->status)
259                         result = _bt_convert_oal_status_to_bt_error(event->status);
260
261                 if (BLUETOOTH_ERROR_NONE == result)
262                         __bt_handle_hid_disconnection(address);
263
264                 if (NULL != req_info) {
265                         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
266                         g_array_append_vals(out_param, &device_address,
267                                         sizeof(bluetooth_device_address_t));
268                         _bt_service_method_return(req_info->context,
269                                         out_param, result);
270                         g_array_free(out_param, TRUE);
271                         _bt_free_info_from_invocation_list(req_info);
272                 }
273                 break;
274         }
275         default:
276                 BT_ERR("Unhandled event: %d", event_type);
277         }
278
279         BT_DBG("-");
280 }
281
282 int _bt_hidhost_initialize()
283 {
284         int result;
285         BT_DBG("+");
286
287         /* Enable HID Profile */
288         result = hid_enable();
289         if (result != OAL_STATUS_SUCCESS) {
290                 BT_ERR("HID Enable failed");
291                 return _bt_convert_oal_status_to_bt_error(result);
292         }
293
294         /* Register HID event handler */
295         _bt_service_register_event_handler_callback(
296                         BT_HID_MODULE, __bt_hid_event_handler);
297
298         return BLUETOOTH_ERROR_NONE;
299 }
300
301 void _bt_hidhost_deinitialize()
302 {
303         BT_DBG("+");
304
305         /* Unregister HID event handler */
306         _bt_service_unregister_event_handler_callback(BT_HID_MODULE);
307
308         /* Clear connected device list */
309         g_slist_free_full(g_connected_list, g_free);
310         g_connected_list = NULL;
311
312         /* Disable HID Profile */
313         hid_disable();
314
315         return;
316 }
317
318 int _bt_hid_connect(bluetooth_device_address_t *device_address)
319 {
320         int result;
321         char address[BT_ADDRESS_STRING_SIZE];
322         bt_address_t bd_addr;
323
324         BT_DBG("+");
325         _bt_convert_addr_type_to_string(address, device_address->addr);
326         BT_INFO("HID connect called for [%s]", address);
327
328         if (TRUE == __bt_is_hid_device_connected(address)) {
329                 BT_ERR("HID device already connected");
330                 return BLUETOOTH_ERROR_ALREADY_CONNECT;
331         }
332
333         memset(&bd_addr, 0x00, sizeof(bt_address_t));
334         memcpy(bd_addr.addr, device_address->addr, BT_ADDRESS_BYTES_NUM);
335
336         result = hid_connect(&bd_addr);
337         if (result != OAL_STATUS_SUCCESS) {
338                 BT_ERR("hid_connect error: [%d]", result);
339                 return _bt_convert_oal_status_to_bt_error(result);
340         }
341         return BLUETOOTH_ERROR_NONE;
342 }
343
344 int _bt_hid_disconnect(bluetooth_device_address_t *device_address)
345 {
346         int result;
347         char address[BT_ADDRESS_STRING_SIZE];
348         bt_address_t bd_addr;
349
350         BT_DBG("+");
351         _bt_convert_addr_type_to_string(address, device_address->addr);
352         BT_INFO("HID disconnect called for [%s]", address);
353
354         memset(&bd_addr, 0x00, sizeof(bt_address_t));
355         memcpy(bd_addr.addr, device_address->addr, BT_ADDRESS_BYTES_NUM);
356
357         result = hid_disconnect(&bd_addr);
358         if (result != OAL_STATUS_SUCCESS) {
359                 BT_ERR("hid_disconnect error: [%d]", result);
360                 return _bt_convert_oal_status_to_bt_error(result);
361         }
362         return BLUETOOTH_ERROR_NONE;
363 }