1 /******************************************************************************
2 *
3 * Copyright 2016 The Android Open Source Project
4 * Copyright 2002-2012 Broadcom Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19
20 /******************************************************************************
21 *
22 * This file contains the HID Device API entry points
23 *
24 ******************************************************************************/
25
26 #include "hidd_api.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "btm_api.h"
33 #include "hidd_int.h"
34 #include "hiddefs.h"
35 #include "osi/include/allocator.h"
36 #include "stack/btm/btm_sec.h"
37 #include "stack/include/bt_types.h"
38 #include "types/bluetooth/uuid.h"
39 #include "types/raw_address.h"
40
41 tHID_DEV_CTB hd_cb;
42
43 /*******************************************************************************
44 *
45 * Function HID_DevInit
46 *
47 * Description Initializes control block
48 *
49 * Returns void
50 *
51 ******************************************************************************/
HID_DevInit(void)52 void HID_DevInit(void) {
53 uint8_t log_level = hd_cb.trace_level;
54
55 HIDD_TRACE_API("%s", __func__);
56
57 memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
58 hd_cb.trace_level = log_level;
59 }
60
61 /*******************************************************************************
62 *
63 * Function HID_DevSetTraceLevel
64 *
65 * Description This function sets the trace level for HID Dev. If called
66 *with
67 * a value of 0xFF, it simply reads the current trace level.
68 *
69 * Returns the new (current) trace level
70 *
71 ******************************************************************************/
HID_DevSetTraceLevel(uint8_t new_level)72 uint8_t HID_DevSetTraceLevel(uint8_t new_level) {
73 if (new_level != 0xFF) hd_cb.trace_level = new_level;
74
75 return (hd_cb.trace_level);
76 }
77
78 /*******************************************************************************
79 *
80 * Function HID_DevRegister
81 *
82 * Description Registers HID device with lower layers
83 *
84 * Returns tHID_STATUS
85 *
86 ******************************************************************************/
HID_DevRegister(tHID_DEV_HOST_CALLBACK * host_cback)87 tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) {
88 tHID_STATUS st;
89
90 HIDD_TRACE_API("%s", __func__);
91
92 if (hd_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
93
94 if (host_cback == NULL) return HID_ERR_INVALID_PARAM;
95
96 /* Register with L2CAP */
97 st = hidd_conn_reg();
98 if (st != HID_SUCCESS) return st;
99
100 hd_cb.callback = host_cback;
101 hd_cb.reg_flag = TRUE;
102
103 if (hd_cb.pending_data) {
104 osi_free(hd_cb.pending_data);
105 hd_cb.pending_data = NULL;
106 }
107
108 return (HID_SUCCESS);
109 }
110
111 /*******************************************************************************
112 *
113 * Function HID_DevDeregister
114 *
115 * Description Deregisters HID device with lower layers
116 *
117 * Returns tHID_STATUS
118 *
119 ******************************************************************************/
HID_DevDeregister(void)120 tHID_STATUS HID_DevDeregister(void) {
121 HIDD_TRACE_API("%s", __func__);
122
123 if (!hd_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
124
125 hidd_conn_dereg();
126
127 hd_cb.reg_flag = FALSE;
128
129 return (HID_SUCCESS);
130 }
131
132 /*******************************************************************************
133 *
134 * Function HID_DevAddRecord
135 *
136 * Description Creates SDP record for HID device
137 *
138 * Returns tHID_STATUS
139 *
140 ******************************************************************************/
HID_DevAddRecord(uint32_t handle,char * p_name,char * p_description,char * p_provider,uint16_t subclass,uint16_t desc_len,uint8_t * p_desc_data)141 tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description,
142 char* p_provider, uint16_t subclass,
143 uint16_t desc_len, uint8_t* p_desc_data) {
144 bool result = TRUE;
145
146 HIDD_TRACE_API("%s", __func__);
147
148 // Service Class ID List
149 if (result) {
150 uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
151 result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
152 }
153
154 // Protocol Descriptor List
155 if (result) {
156 tSDP_PROTOCOL_ELEM proto_list[2];
157
158 proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
159 proto_list[0].num_params = 1;
160 proto_list[0].params[0] = BT_PSM_HIDC;
161
162 proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
163 proto_list[1].num_params = 0;
164
165 result &= SDP_AddProtocolList(handle, 2, proto_list);
166 }
167
168 // Language Base Attribute ID List
169 if (result) {
170 result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH,
171 LANG_ID_CHAR_ENCODE_UTF8,
172 LANGUAGE_BASE_ID);
173 }
174
175 // Additional Protocol Descriptor List
176 if (result) {
177 tSDP_PROTO_LIST_ELEM add_proto_list;
178
179 add_proto_list.num_elems = 2;
180 add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
181 add_proto_list.list_elem[0].num_params = 1;
182 add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
183 add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
184 add_proto_list.list_elem[1].num_params = 0;
185
186 result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
187 }
188
189 // Service Name (O)
190 // Service Description (O)
191 // Provider Name (O)
192 if (result) {
193 const char* srv_name = p_name;
194 const char* srv_desc = p_description;
195 const char* provider_name = p_provider;
196
197 result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
198 strlen(srv_name) + 1, (uint8_t*)srv_name);
199
200 result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
201 TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
202 (uint8_t*)srv_desc);
203
204 result &=
205 SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
206 strlen(provider_name) + 1, (uint8_t*)provider_name);
207 }
208
209 // Bluetooth Profile Descriptor List
210 if (result) {
211 const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
212 const uint16_t version = 0x0100;
213
214 result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
215 }
216
217 // HID Parser Version
218 if (result) {
219 uint8_t* p;
220 const uint16_t rel_num = 0x0100;
221 const uint16_t parser_version = 0x0111;
222 const uint16_t prof_ver = 0x0100;
223 const uint8_t dev_subclass = subclass;
224 const uint8_t country_code = 0x21;
225 const uint8_t bool_false = 0x00;
226 const uint8_t bool_true = 0x01;
227 uint16_t temp;
228
229 p = (uint8_t*)&temp;
230 UINT16_TO_BE_STREAM(p, rel_num);
231 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM,
232 UINT_DESC_TYPE, 2, (uint8_t*)&temp);
233
234 p = (uint8_t*)&temp;
235 UINT16_TO_BE_STREAM(p, parser_version);
236 result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION,
237 UINT_DESC_TYPE, 2, (uint8_t*)&temp);
238
239 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS,
240 UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass);
241
242 result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE,
243 1, (uint8_t*)&country_code);
244
245 result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE,
246 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
247
248 result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE,
249 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
250
251 {
252 static uint8_t cdt = 0x22;
253 uint8_t* p_buf;
254 uint8_t seq_len = 4 + desc_len;
255
256 if (desc_len > HIDD_APP_DESCRIPTOR_LEN) {
257 HIDD_TRACE_ERROR("%s: descriptor length = %d, larger than max %d",
258 __func__, desc_len, HIDD_APP_DESCRIPTOR_LEN);
259 return HID_ERR_NOT_REGISTERED;
260 };
261
262 p_buf = (uint8_t*)osi_malloc(HIDD_APP_DESCRIPTOR_LEN + 6);
263
264 if (p_buf == NULL) {
265 HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ",
266 __func__);
267 return HID_ERR_NOT_REGISTERED;
268 }
269
270 p = p_buf;
271
272 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
273
274 UINT8_TO_BE_STREAM(p, seq_len);
275
276 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
277 UINT8_TO_BE_STREAM(p, cdt);
278
279 UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
280 UINT8_TO_BE_STREAM(p, desc_len);
281 ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
282
283 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST,
284 DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
285
286 osi_free(p_buf);
287 }
288
289 {
290 uint8_t lang_buf[8];
291 p = lang_buf;
292 uint8_t seq_len = 6;
293 uint16_t lang_english = 0x0409;
294 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
295 UINT8_TO_BE_STREAM(p, seq_len);
296 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
297 UINT16_TO_BE_STREAM(p, lang_english);
298 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
299 UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
300 result &=
301 SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE,
302 DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
303 }
304
305 result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER,
306 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
307
308 result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE,
309 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false);
310
311 result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE,
312 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
313
314 result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE,
315 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
316
317 p = (uint8_t*)&temp;
318 UINT16_TO_BE_STREAM(p, prof_ver);
319 result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION,
320 UINT_DESC_TYPE, 2, (uint8_t*)&temp);
321 }
322
323 if (result) {
324 uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
325 result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
326 &browse_group);
327 }
328
329 if (!result) {
330 HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
331
332 return HID_ERR_NOT_REGISTERED;
333 }
334
335 return HID_SUCCESS;
336 }
337
338 /*******************************************************************************
339 *
340 * Function HID_DevSendReport
341 *
342 * Description Sends report
343 *
344 * Returns tHID_STATUS
345 *
346 ******************************************************************************/
HID_DevSendReport(uint8_t channel,uint8_t type,uint8_t id,uint16_t len,uint8_t * p_data)347 tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
348 uint16_t len, uint8_t* p_data) {
349 HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel,
350 type, id, len);
351
352 if (channel == HID_CHANNEL_CTRL) {
353 return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len,
354 p_data);
355 }
356
357 if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
358 // on INTR we can only send INPUT
359 return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA,
360 HID_PAR_REP_TYPE_INPUT, id, len, p_data);
361 }
362
363 return HID_ERR_INVALID_PARAM;
364 }
365
366 /*******************************************************************************
367 *
368 * Function HID_DevVirtualCableUnplug
369 *
370 * Description Sends Virtual Cable Unplug
371 *
372 * Returns tHID_STATUS
373 *
374 ******************************************************************************/
HID_DevVirtualCableUnplug(void)375 tHID_STATUS HID_DevVirtualCableUnplug(void) {
376 HIDD_TRACE_API("%s", __func__);
377
378 return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL,
379 HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
380 }
381
382 /*******************************************************************************
383 *
384 * Function HID_DevPlugDevice
385 *
386 * Description Establishes virtual cable to given host
387 *
388 * Returns tHID_STATUS
389 *
390 ******************************************************************************/
HID_DevPlugDevice(const RawAddress & addr)391 tHID_STATUS HID_DevPlugDevice(const RawAddress& addr) {
392 hd_cb.device.in_use = TRUE;
393 hd_cb.device.addr = addr;
394
395 return HID_SUCCESS;
396 }
397
398 /*******************************************************************************
399 *
400 * Function HID_DevUnplugDevice
401 *
402 * Description Unplugs virtual cable from given host
403 *
404 * Returns tHID_STATUS
405 *
406 ******************************************************************************/
HID_DevUnplugDevice(const RawAddress & addr)407 tHID_STATUS HID_DevUnplugDevice(const RawAddress& addr) {
408 if (hd_cb.device.addr == addr) {
409 hd_cb.device.in_use = FALSE;
410 hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
411 hd_cb.device.conn.ctrl_cid = 0;
412 hd_cb.device.conn.intr_cid = 0;
413 }
414
415 return HID_SUCCESS;
416 }
417
418 /*******************************************************************************
419 *
420 * Function HID_DevConnect
421 *
422 * Description Connects to device
423 *
424 * Returns tHID_STATUS
425 *
426 ******************************************************************************/
HID_DevConnect(void)427 tHID_STATUS HID_DevConnect(void) {
428 if (!hd_cb.reg_flag) {
429 return HID_ERR_NOT_REGISTERED;
430 }
431
432 if (!hd_cb.device.in_use) {
433 return HID_ERR_INVALID_PARAM;
434 }
435
436 if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
437 return HID_ERR_ALREADY_CONN;
438 }
439
440 return hidd_conn_initiate();
441 }
442
443 /*******************************************************************************
444 *
445 * Function HID_DevDisconnect
446 *
447 * Description Disconnects from device
448 *
449 * Returns tHID_STATUS
450 *
451 ******************************************************************************/
HID_DevDisconnect(void)452 tHID_STATUS HID_DevDisconnect(void) {
453 if (!hd_cb.reg_flag) {
454 return HID_ERR_NOT_REGISTERED;
455 }
456
457 if (!hd_cb.device.in_use) {
458 return HID_ERR_INVALID_PARAM;
459 }
460
461 if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
462 /* If we are still trying to connect, just close the connection. */
463 if (hd_cb.device.conn.conn_state != HID_CONN_STATE_UNUSED) {
464 tHID_STATUS ret = hidd_conn_disconnect();
465 hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
466 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
467 HID_ERR_DISCONNECTING, NULL);
468 return ret;
469 }
470 return HID_ERR_NO_CONNECTION;
471 }
472
473 return hidd_conn_disconnect();
474 }
475
476 /*******************************************************************************
477 *
478 * Function HID_DevSetIncomingPolicy
479 *
480 * Description Sets policy for incoming connections (allowed/disallowed)
481 *
482 * Returns tHID_STATUS
483 *
484 ******************************************************************************/
HID_DevSetIncomingPolicy(bool allow)485 tHID_STATUS HID_DevSetIncomingPolicy(bool allow) {
486 hd_cb.allow_incoming = allow;
487
488 return HID_SUCCESS;
489 }
490
491 /*******************************************************************************
492 *
493 * Function HID_DevReportError
494 *
495 * Description Reports error for Set Report via HANDSHAKE
496 *
497 * Returns tHID_STATUS
498 *
499 ******************************************************************************/
HID_DevReportError(uint8_t error)500 tHID_STATUS HID_DevReportError(uint8_t error) {
501 uint8_t handshake_param;
502
503 HIDD_TRACE_API("%s: error = %d", __func__, error);
504
505 switch (error) {
506 case HID_PAR_HANDSHAKE_RSP_SUCCESS:
507 case HID_PAR_HANDSHAKE_RSP_NOT_READY:
508 case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
509 case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
510 case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
511 case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
512 case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
513 handshake_param = error;
514 break;
515 default:
516 handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
517 break;
518 }
519
520 return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0,
521 NULL);
522 }
523
524 /*******************************************************************************
525 *
526 * Function HID_DevGetDevice
527 *
528 * Description Returns the BD Address of virtually cabled device
529 *
530 * Returns tHID_STATUS
531 *
532 ******************************************************************************/
HID_DevGetDevice(RawAddress * addr)533 tHID_STATUS HID_DevGetDevice(RawAddress* addr) {
534 HIDD_TRACE_API("%s", __func__);
535
536 if (hd_cb.device.in_use) {
537 *addr = hd_cb.device.addr;
538 } else {
539 return HID_ERR_NOT_REGISTERED;
540 }
541
542 return HID_SUCCESS;
543 }
544
545 /*******************************************************************************
546 *
547 * Function HID_DevSetIncomingQos
548 *
549 * Description Sets Incoming QoS values for Interrupt L2CAP Channel
550 *
551 * Returns tHID_STATUS
552 *
553 ******************************************************************************/
HID_DevSetIncomingQos(uint8_t service_type,uint32_t token_rate,uint32_t token_bucket_size,uint32_t peak_bandwidth,uint32_t latency,uint32_t delay_variation)554 tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate,
555 uint32_t token_bucket_size,
556 uint32_t peak_bandwidth, uint32_t latency,
557 uint32_t delay_variation) {
558 HIDD_TRACE_API("%s", __func__);
559
560 hd_cb.use_in_qos = TRUE;
561
562 hd_cb.in_qos.service_type = service_type;
563 hd_cb.in_qos.token_rate = token_rate;
564 hd_cb.in_qos.token_bucket_size = token_bucket_size;
565 hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
566 hd_cb.in_qos.latency = latency;
567 hd_cb.in_qos.delay_variation = delay_variation;
568
569 return HID_SUCCESS;
570 }
571
572 /*******************************************************************************
573 *
574 * Function HID_DevSetOutgoingQos
575 *
576 * Description Sets Outgoing QoS values for Interrupt L2CAP Channel
577 *
578 * Returns tHID_STATUS
579 *
580 ******************************************************************************/
HID_DevSetOutgoingQos(uint8_t service_type,uint32_t token_rate,uint32_t token_bucket_size,uint32_t peak_bandwidth,uint32_t latency,uint32_t delay_variation)581 tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate,
582 uint32_t token_bucket_size,
583 uint32_t peak_bandwidth, uint32_t latency,
584 uint32_t delay_variation) {
585 HIDD_TRACE_API("%s", __func__);
586
587 hd_cb.l2cap_intr_cfg.qos_present = TRUE;
588
589 hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
590 hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
591 hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
592 hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
593 hd_cb.l2cap_intr_cfg.qos.latency = latency;
594 hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
595
596 return HID_SUCCESS;
597 }
598