tizen 2.3.1 release
[framework/connectivity/bluez.git] / android / client / if-hh.c
1 /*
2  * Copyright (C) 2013 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <string.h>
21
22 #include <hardware/bluetooth.h>
23 #include <hardware/bt_hh.h>
24
25 #include "if-main.h"
26 #include "pollhandler.h"
27 #include "../hal-utils.h"
28
29 const bthh_interface_t *if_hh = NULL;
30
31 SINTMAP(bthh_protocol_mode_t, -1, "(unknown)")
32         DELEMENT(BTHH_REPORT_MODE),
33         DELEMENT(BTHH_BOOT_MODE),
34         DELEMENT(BTHH_UNSUPPORTED_MODE),
35 ENDMAP
36
37 SINTMAP(bthh_report_type_t, -1, "(unknown)")
38         DELEMENT(BTHH_INPUT_REPORT),
39         DELEMENT(BTHH_OUTPUT_REPORT),
40         DELEMENT(BTHH_FEATURE_REPORT),
41 ENDMAP
42
43 SINTMAP(bthh_connection_state_t, -1, "(unknown)")
44         DELEMENT(BTHH_CONN_STATE_CONNECTED),
45         DELEMENT(BTHH_CONN_STATE_CONNECTING),
46         DELEMENT(BTHH_CONN_STATE_DISCONNECTED),
47         DELEMENT(BTHH_CONN_STATE_DISCONNECTING),
48         DELEMENT(BTHH_CONN_STATE_FAILED_MOUSE_FROM_HOST),
49         DELEMENT(BTHH_CONN_STATE_FAILED_KBD_FROM_HOST),
50         DELEMENT(BTHH_CONN_STATE_FAILED_TOO_MANY_DEVICES),
51         DELEMENT(BTHH_CONN_STATE_FAILED_NO_BTHID_DRIVER),
52         DELEMENT(BTHH_CONN_STATE_FAILED_GENERIC),
53         DELEMENT(BTHH_CONN_STATE_UNKNOWN),
54 ENDMAP
55
56 SINTMAP(bthh_status_t, -1, "(unknown)")
57         DELEMENT(BTHH_OK),
58         DELEMENT(BTHH_HS_HID_NOT_READY),
59         DELEMENT(BTHH_HS_INVALID_RPT_ID),
60         DELEMENT(BTHH_HS_TRANS_NOT_SPT),
61         DELEMENT(BTHH_HS_INVALID_PARAM),
62         DELEMENT(BTHH_HS_ERROR),
63         DELEMENT(BTHH_ERR),
64         DELEMENT(BTHH_ERR_SDP),
65         DELEMENT(BTHH_ERR_PROTO),
66         DELEMENT(BTHH_ERR_DB_FULL),
67         DELEMENT(BTHH_ERR_TOD_UNSPT),
68         DELEMENT(BTHH_ERR_NO_RES),
69         DELEMENT(BTHH_ERR_AUTH_FAILED),
70         DELEMENT(BTHH_ERR_HDL),
71 ENDMAP
72
73 static char connected_device_addr[MAX_ADDR_STR_LEN];
74 /*
75  * Callback for connection state change.
76  * state will have one of the values from bthh_connection_state_t
77  */
78 static void connection_state_cb(bt_bdaddr_t *bd_addr,
79                                                 bthh_connection_state_t state)
80 {
81         char addr[MAX_ADDR_STR_LEN];
82
83         haltest_info("%s: bd_addr=%s connection_state=%s\n", __func__,
84                                         bt_bdaddr_t2str(bd_addr, addr),
85                                         bthh_connection_state_t2str(state));
86         if (state == BTHH_CONN_STATE_CONNECTED)
87                 strcpy(connected_device_addr, addr);
88 }
89
90 /*
91  * Callback for virtual unplug api.
92  * the status of the virtual unplug
93  */
94 static void virtual_unplug_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
95 {
96         char addr[MAX_ADDR_STR_LEN];
97
98         haltest_info("%s: bd_addr=%s hh_status=%s\n", __func__,
99                                                 bt_bdaddr_t2str(bd_addr, addr),
100                                                 bthh_status_t2str(hh_status));
101 }
102
103 /* Callback for Android 5.0 handshake api. */
104 #if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
105 static void handshake_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status)
106 {
107         char addr[MAX_ADDR_STR_LEN];
108
109         haltest_info("%s: bd_addr=%s hh_status=%s\n", __func__,
110                                                 bt_bdaddr_t2str(bd_addr, addr),
111                                                 bthh_status_t2str(hh_status));
112 }
113 #endif
114
115 /*
116  * Callback for get hid info
117  * hid_info will contain attr_mask, sub_class, app_id, vendor_id, product_id,
118  * version, ctry_code, len
119  */
120 static void hid_info_cb(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
121 {
122         char addr[MAX_ADDR_STR_LEN];
123
124         /* TODO: bluedroid does not seem to ever call this callback */
125         haltest_info("%s: bd_addr=%s\n", __func__,
126                                                 bt_bdaddr_t2str(bd_addr, addr));
127 }
128
129 /*
130  * Callback for get/set protocol api.
131  * the protocol mode is one of the value from bthh_protocol_mode_t
132  */
133 static void protocol_mode_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
134                                                 bthh_protocol_mode_t mode)
135 {
136         char addr[MAX_ADDR_STR_LEN];
137
138         haltest_info("%s: bd_addr=%s hh_status=%s mode=%s\n", __func__,
139                                         bt_bdaddr_t2str(bd_addr, addr),
140                                         bthh_status_t2str(hh_status),
141                                         bthh_protocol_mode_t2str(mode));
142 }
143
144 /* Callback for get/set_idle_time api. */
145 static void idle_time_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
146                                                                 int idle_rate)
147 {
148         char addr[MAX_ADDR_STR_LEN];
149
150         haltest_info("%s: bd_addr=%s hh_status=%s idle_rate=%d\n", __func__,
151                                 bt_bdaddr_t2str(bd_addr, addr),
152                                 bthh_status_t2str(hh_status), idle_rate);
153 }
154
155
156 /*
157  * Callback for get report api.
158  * if status is ok rpt_data contains the report data
159  */
160 static void get_report_cb(bt_bdaddr_t *bd_addr, bthh_status_t hh_status,
161                                                 uint8_t *rpt_data, int rpt_size)
162 {
163         char addr[MAX_ADDR_STR_LEN];
164
165         /* TODO: print actual report */
166         haltest_info("%s: bd_addr=%s hh_status=%s rpt_size=%d\n", __func__,
167                                         bt_bdaddr_t2str(bd_addr, addr),
168                                         bthh_status_t2str(hh_status), rpt_size);
169 }
170
171 static bthh_callbacks_t bthh_callbacks = {
172         .size = sizeof(bthh_callbacks),
173         .connection_state_cb = connection_state_cb,
174         .hid_info_cb = hid_info_cb,
175         .protocol_mode_cb = protocol_mode_cb,
176         .idle_time_cb = idle_time_cb,
177         .get_report_cb = get_report_cb,
178         .virtual_unplug_cb = virtual_unplug_cb,
179 #if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
180         .handshake_cb = handshake_cb
181 #endif
182 };
183
184 /* init */
185
186 static void init_p(int argc, const char **argv)
187 {
188         RETURN_IF_NULL(if_hh);
189
190         EXEC(if_hh->init, &bthh_callbacks);
191 }
192
193 /* connect */
194
195 static void connect_c(int argc, const char **argv, enum_func *enum_func,
196                                                                 void **user)
197 {
198         if (argc == 3) {
199                 *user = (void *) connected_device_addr;
200                 *enum_func = enum_one_string;
201         }
202 }
203
204 static void connect_p(int argc, const char **argv)
205 {
206         bt_bdaddr_t addr;
207
208         RETURN_IF_NULL(if_hh);
209         VERIFY_ADDR_ARG(2, &addr);
210
211         EXEC(if_hh->connect, &addr);
212 }
213
214 /* disconnect */
215
216 /* Same completion as connect_c */
217 #define disconnect_c connect_c
218
219 static void disconnect_p(int argc, const char **argv)
220 {
221         bt_bdaddr_t addr;
222
223         RETURN_IF_NULL(if_hh);
224         VERIFY_ADDR_ARG(2, &addr);
225
226         EXEC(if_hh->disconnect, &addr);
227 }
228
229 /* virtual_unplug */
230
231 /* Same completion as connect_c */
232 #define virtual_unplug_c connect_c
233
234 static void virtual_unplug_p(int argc, const char **argv)
235 {
236         bt_bdaddr_t addr;
237
238         RETURN_IF_NULL(if_hh);
239         VERIFY_ADDR_ARG(2, &addr);
240
241         EXEC(if_hh->virtual_unplug, &addr);
242 }
243
244 /* set_info */
245
246 /* Same completion as connect_c */
247 #define set_info_c connect_c
248
249 static void set_info_p(int argc, const char **argv)
250 {
251         bt_bdaddr_t addr;
252         bthh_hid_info_t hid_info;
253
254         RETURN_IF_NULL(if_hh);
255         VERIFY_ADDR_ARG(2, &addr);
256
257         memset(&hid_info, 0, sizeof(hid_info));
258
259         /*
260          * This command is intentionally not supported. See comment from
261          * bt_hid_info() in android/hidhost.c
262          */
263         EXEC(if_hh->set_info, &addr, hid_info);
264 }
265
266 /* get_protocol */
267
268 static void get_protocol_c(int argc, const char **argv, enum_func *enum_func,
269                                                                 void **user)
270 {
271         if (argc == 3) {
272                 *user = connected_device_addr;
273                 *enum_func = enum_one_string;
274         } else if (argc == 4) {
275                 *user = TYPE_ENUM(bthh_protocol_mode_t);
276                 *enum_func = enum_defines;
277         }
278 }
279
280 static void get_protocol_p(int argc, const char **argv)
281 {
282         bt_bdaddr_t addr;
283         bthh_protocol_mode_t protocolMode;
284
285         RETURN_IF_NULL(if_hh);
286         VERIFY_ADDR_ARG(2, &addr);
287
288         if (argc < 4) {
289                 haltest_error("No protocol mode specified\n");
290                 return;
291         }
292         protocolMode = str2bthh_protocol_mode_t(argv[3]);
293
294         EXEC(if_hh->get_protocol, &addr, protocolMode);
295 }
296
297 /* set_protocol */
298
299 /* Same completion as get_protocol_c */
300 #define set_protocol_c get_protocol_c
301
302 static void set_protocol_p(int argc, const char **argv)
303 {
304         bt_bdaddr_t addr;
305         bthh_protocol_mode_t protocolMode;
306
307         RETURN_IF_NULL(if_hh);
308         VERIFY_ADDR_ARG(2, &addr);
309
310         if (argc < 4) {
311                 haltest_error("No protocol mode specified\n");
312                 return;
313         }
314         protocolMode = str2bthh_protocol_mode_t(argv[3]);
315
316         EXEC(if_hh->set_protocol, &addr, protocolMode);
317 }
318
319 /* get_report */
320
321 static void get_report_c(int argc, const char **argv, enum_func *enum_func,
322                                                                 void **user)
323 {
324         if (argc == 3) {
325                 *user = connected_device_addr;
326                 *enum_func = enum_one_string;
327         } else if (argc == 4) {
328                 *user = TYPE_ENUM(bthh_report_type_t);
329                 *enum_func = enum_defines;
330         }
331 }
332
333 static void get_report_p(int argc, const char **argv)
334 {
335         bt_bdaddr_t addr;
336         bthh_report_type_t reportType;
337         uint8_t reportId;
338         int bufferSize;
339
340         RETURN_IF_NULL(if_hh);
341         VERIFY_ADDR_ARG(2, &addr);
342
343         if (argc < 4) {
344                 haltest_error("No report type specified\n");
345                 return;
346         }
347         reportType = str2bthh_report_type_t(argv[3]);
348
349         if (argc < 5) {
350                 haltest_error("No reportId specified\n");
351                 return;
352         }
353         reportId = (uint8_t) atoi(argv[4]);
354
355         if (argc < 6) {
356                 haltest_error("No bufferSize specified\n");
357                 return;
358         }
359         bufferSize = atoi(argv[5]);
360
361         EXEC(if_hh->get_report, &addr, reportType, reportId, bufferSize);
362 }
363
364 /* set_report */
365
366 static void set_report_c(int argc, const char **argv, enum_func *enum_func,
367                                                                 void **user)
368 {
369         if (argc == 3) {
370                 *user = connected_device_addr;
371                 *enum_func = enum_one_string;
372         } else if (argc == 4) {
373                 *user = TYPE_ENUM(bthh_report_type_t);
374                 *enum_func = enum_defines;
375         }
376 }
377
378 static void set_report_p(int argc, const char **argv)
379 {
380         bt_bdaddr_t addr;
381         bthh_report_type_t reportType;
382
383         RETURN_IF_NULL(if_hh);
384         VERIFY_ADDR_ARG(2, &addr);
385
386         if (argc <= 3) {
387                 haltest_error("No report type specified\n");
388                 return;
389         }
390         reportType = str2bthh_report_type_t(argv[3]);
391
392         if (argc <= 4) {
393                 haltest_error("No report specified\n");
394                 return;
395         }
396
397         EXEC(if_hh->set_report, &addr, reportType, (char *) argv[4]);
398 }
399
400 /* send_data */
401
402 static void send_data_c(int argc, const char **argv, enum_func *enum_func,
403                                                                 void **user)
404 {
405         if (argc == 3) {
406                 *user = connected_device_addr;
407                 *enum_func = enum_one_string;
408         }
409 }
410
411 static void send_data_p(int argc, const char **argv)
412 {
413         bt_bdaddr_t addr;
414
415         RETURN_IF_NULL(if_hh);
416         VERIFY_ADDR_ARG(2, &addr);
417
418         if (argc <= 3) {
419                 haltest_error("No data to send specified\n");
420                 return;
421         }
422
423         EXEC(if_hh->send_data, &addr, (char *) argv[3]);
424 }
425
426 /* cleanup */
427
428 static void cleanup_p(int argc, const char **argv)
429 {
430         RETURN_IF_NULL(if_hh);
431
432         EXECV(if_hh->cleanup);
433 }
434
435 /* Methods available in bthh_interface_t */
436 static struct method methods[] = {
437         STD_METHOD(init),
438         STD_METHODCH(connect, "<addr>"),
439         STD_METHODCH(disconnect, "<addr>"),
440         STD_METHODCH(virtual_unplug, "<addr>"),
441         STD_METHODCH(set_info, "<addr>"),
442         STD_METHODCH(get_protocol, "<addr> <mode>"),
443         STD_METHODCH(set_protocol, "<addr> <mode>"),
444         STD_METHODCH(get_report, "<addr> <type> <report_id> <size>"),
445         STD_METHODCH(set_report, "<addr> <type> <hex_encoded_report>"),
446         STD_METHODCH(send_data, "<addr> <hex_encoded_data>"),
447         STD_METHOD(cleanup),
448         END_METHOD
449 };
450
451 const struct interface hh_if = {
452         .name = "hidhost",
453         .methods = methods
454 };