1 /******************************************************************************
2 *
3 * Copyright 2002-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * This file contains the HID HOST API entry points
22 *
23 ******************************************************************************/
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "bt_common.h"
30 #include "bt_types.h"
31 #include "btm_api.h"
32 #include "btm_int.h"
33 #include "btu.h"
34 #include "hiddefs.h"
35 #include "hidh_api.h"
36 #include "hidh_int.h"
37
38 using bluetooth::Uuid;
39
40 tHID_HOST_CTB hh_cb;
41
42 static void hidh_search_callback(uint16_t sdp_result);
43
44 /*******************************************************************************
45 *
46 * Function HID_HostGetSDPRecord
47 *
48 * Description This function reads the device SDP record
49 *
50 * Returns tHID_STATUS
51 *
52 ******************************************************************************/
HID_HostGetSDPRecord(const RawAddress & addr,tSDP_DISCOVERY_DB * p_db,uint32_t db_len,tHID_HOST_SDP_CALLBACK * sdp_cback)53 tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr,
54 tSDP_DISCOVERY_DB* p_db, uint32_t db_len,
55 tHID_HOST_SDP_CALLBACK* sdp_cback) {
56
57 if (hh_cb.sdp_busy) return HID_ERR_SDP_BUSY;
58
59 hh_cb.p_sdp_db = p_db;
60 Uuid uuid_list = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
61 SDP_InitDiscoveryDb(p_db, db_len, 1, &uuid_list, 0, NULL);
62
63 if (SDP_ServiceSearchRequest(addr, p_db, hidh_search_callback)) {
64 hh_cb.sdp_cback = sdp_cback;
65 hh_cb.sdp_busy = true;
66 return HID_SUCCESS;
67 } else
68 return HID_ERR_NO_RESOURCES;
69 }
70
hidh_get_str_attr(tSDP_DISC_REC * p_rec,uint16_t attr_id,uint16_t max_len,char * str)71 void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len,
72 char* str) {
73 tSDP_DISC_ATTR* p_attr;
74 uint16_t name_len;
75
76 p_attr = SDP_FindAttributeInRec(p_rec, attr_id);
77 if (p_attr != NULL) {
78 name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
79 if (name_len < max_len) {
80 memcpy(str, (char*)p_attr->attr_value.v.array, name_len);
81 str[name_len] = '\0';
82 } else {
83 memcpy(str, (char*)p_attr->attr_value.v.array, max_len - 1);
84 str[max_len - 1] = '\0';
85 }
86 } else
87 str[0] = '\0';
88 }
89
hidh_search_callback(uint16_t sdp_result)90 static void hidh_search_callback(uint16_t sdp_result) {
91 tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db;
92 tSDP_DISC_REC* p_rec;
93 tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
94 tHID_DEV_SDP_INFO* p_nvi = &hh_cb.sdp_rec;
95 uint16_t attr_mask = 0;
96
97
98 hh_cb.sdp_busy = false;
99
100 if (sdp_result != SDP_SUCCESS) {
101 hh_cb.sdp_cback(sdp_result, 0, NULL);
102 return;
103 }
104
105 Uuid hid_uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
106 p_rec = SDP_FindServiceUUIDInDb(p_db, hid_uuid, NULL);
107 if (p_rec == NULL) {
108 hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
109 return;
110 }
111
112 memset(&hh_cb.sdp_rec, 0, sizeof(tHID_DEV_SDP_INFO));
113
114 /* First, verify the mandatory fields we care about */
115 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) ==
116 NULL) ||
117 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) ||
118 ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL) ||
119 (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) !=
120 DATA_ELE_SEQ_DESC_TYPE) ||
121 ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL) ||
122 ((p_repdesc = p_subattr2->p_next_attr) == NULL) ||
123 (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE)) {
124 hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
125 return;
126 }
127
128 p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type);
129 if (p_nvi->dscp_info.dl_len != 0)
130 p_nvi->dscp_info.dsc_list = (uint8_t*)&p_repdesc->attr_value;
131
132 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) !=
133 NULL) &&
134 (p_attr->attr_value.v.u8)) {
135 attr_mask |= HID_VIRTUAL_CABLE;
136 }
137
138 if (((p_attr = SDP_FindAttributeInRec(
139 p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
140 (p_attr->attr_value.v.u8)) {
141 attr_mask |= HID_RECONN_INIT;
142 }
143
144 if (((p_attr = SDP_FindAttributeInRec(
145 p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
146 (p_attr->attr_value.v.u8)) {
147 attr_mask |= HID_NORMALLY_CONNECTABLE;
148 }
149
150 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_SDP_DISABLE)) !=
151 NULL) &&
152 (p_attr->attr_value.v.u8)) {
153 attr_mask |= HID_SDP_DISABLE;
154 }
155
156 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_BATTERY_POWER)) !=
157 NULL) &&
158 (p_attr->attr_value.v.u8)) {
159 attr_mask |= HID_BATTERY_POWER;
160 }
161
162 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_REMOTE_WAKE)) !=
163 NULL) &&
164 (p_attr->attr_value.v.u8)) {
165 attr_mask |= HID_REMOTE_WAKE;
166 }
167
168 hidh_get_str_attr(p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN,
169 p_nvi->svc_name);
170 hidh_get_str_attr(p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN,
171 p_nvi->svc_descr);
172 hidh_get_str_attr(p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN,
173 p_nvi->prov_name);
174
175 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DEVICE_RELNUM)) !=
176 NULL)) {
177 p_nvi->rel_num = p_attr->attr_value.v.u16;
178 }
179
180 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_COUNTRY_CODE)) !=
181 NULL)) {
182 p_nvi->ctry_code = p_attr->attr_value.v.u8;
183 }
184
185 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) !=
186 NULL)) {
187 p_nvi->sub_class = p_attr->attr_value.v.u8;
188 }
189
190 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_PARSER_VERSION)) !=
191 NULL)) {
192 p_nvi->hpars_ver = p_attr->attr_value.v.u16;
193 }
194
195 if (((p_attr = SDP_FindAttributeInRec(
196 p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL)) {
197 attr_mask |= HID_SUP_TOUT_AVLBL;
198 p_nvi->sup_timeout = p_attr->attr_value.v.u16;
199 }
200
201 if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) !=
202 NULL)) {
203 attr_mask |= HID_SSR_MAX_LATENCY;
204 p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
205 } else
206 p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
207
208 if (((p_attr = SDP_FindAttributeInRec(
209 p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL)) {
210 attr_mask |= HID_SSR_MIN_TOUT;
211 p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
212 } else
213 p_nvi->ssr_min_tout = HID_SSR_PARAM_INVALID;
214
215 hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
216 hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
217 }
218
219 /*******************************************************************************
220 *
221 * Function HID_HostInit
222 *
223 * Description This function initializes the control block and trace
224 * variable
225 *
226 * Returns void
227 *
228 ******************************************************************************/
HID_HostInit(void)229 void HID_HostInit(void) {
230 uint8_t log_level = hh_cb.trace_level;
231 memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
232 hh_cb.trace_level = log_level;
233 }
234
235 /*******************************************************************************
236 *
237 * Function HID_HostSetTraceLevel
238 *
239 * Description This function sets the trace level for HID Host. If called
240 * with 0xFF, it simply reads the current trace level.
241 *
242 * Returns the new (current) trace level
243 *
244 ******************************************************************************/
HID_HostSetTraceLevel(uint8_t new_level)245 uint8_t HID_HostSetTraceLevel(uint8_t new_level) {
246 if (new_level != 0xFF) hh_cb.trace_level = new_level;
247
248 return (hh_cb.trace_level);
249 }
250
251 /*******************************************************************************
252 *
253 * Function HID_HostRegister
254 *
255 * Description This function registers HID-Host with lower layers
256 *
257 * Returns tHID_STATUS
258 *
259 ******************************************************************************/
HID_HostRegister(tHID_HOST_DEV_CALLBACK * dev_cback)260 tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback) {
261 tHID_STATUS st;
262
263 if (hh_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
264
265 if (dev_cback == NULL) return HID_ERR_INVALID_PARAM;
266
267 /* Register with L2CAP */
268 st = hidh_conn_reg();
269 if (st != HID_SUCCESS) {
270 return st;
271 }
272
273 hh_cb.callback = dev_cback;
274 hh_cb.reg_flag = true;
275
276 for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
277 hh_cb.devices[i].conn.process_repage_timer =
278 alarm_new("hid_devices_conn.process_repage_timer");
279 }
280 return (HID_SUCCESS);
281 }
282
283 /*******************************************************************************
284 *
285 * Function HID_HostDeregister
286 *
287 * Description This function is called when the host is about power down.
288 *
289 * Returns tHID_STATUS
290 *
291 ******************************************************************************/
HID_HostDeregister(void)292 tHID_STATUS HID_HostDeregister(void) {
293 uint8_t i;
294
295 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
296
297 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
298 HID_HostRemoveDev(i);
299 alarm_free(hh_cb.devices[i].conn.process_repage_timer);
300 }
301
302 hidh_conn_dereg();
303 hh_cb.reg_flag = false;
304
305 return (HID_SUCCESS);
306 }
307
308 /*******************************************************************************
309 *
310 * Function HID_HostAddDev
311 *
312 * Description This is called so HID-host may manage this device.
313 *
314 * Returns tHID_STATUS
315 *
316 ******************************************************************************/
HID_HostAddDev(const RawAddress & addr,uint16_t attr_mask,uint8_t * handle)317 tHID_STATUS HID_HostAddDev(const RawAddress& addr, uint16_t attr_mask,
318 uint8_t* handle) {
319 int i;
320 /* Find an entry for this device in hh_cb.devices array */
321 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
322
323 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
324 if ((hh_cb.devices[i].in_use) && addr == hh_cb.devices[i].addr) break;
325 }
326
327 if (i == HID_HOST_MAX_DEVICES) {
328 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
329 if (!hh_cb.devices[i].in_use) break;
330 }
331 }
332
333 if (i == HID_HOST_MAX_DEVICES) return HID_ERR_NO_RESOURCES;
334
335 if (!hh_cb.devices[i].in_use) {
336 hh_cb.devices[i].in_use = true;
337 hh_cb.devices[i].addr = addr;
338 hh_cb.devices[i].state = HID_DEV_NO_CONN;
339 hh_cb.devices[i].conn_tries = 0;
340 }
341
342 if (attr_mask != HID_ATTR_MASK_IGNORE) hh_cb.devices[i].attr_mask = attr_mask;
343
344 *handle = i;
345
346 return (HID_SUCCESS);
347 }
348
349 /*******************************************************************************
350 *
351 * Function HID_HostRemoveDev
352 *
353 * Description This removes the device from the list of devices that the
354 * host has to manage.
355 *
356 * Returns tHID_STATUS
357 *
358 ******************************************************************************/
HID_HostRemoveDev(uint8_t dev_handle)359 tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle) {
360 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
361
362 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
363 (!hh_cb.devices[dev_handle].in_use))
364 return HID_ERR_INVALID_PARAM;
365
366 HID_HostCloseDev(dev_handle);
367 hh_cb.devices[dev_handle].in_use = false;
368 hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
369 hh_cb.devices[dev_handle].conn.ctrl_cid =
370 hh_cb.devices[dev_handle].conn.intr_cid = 0;
371 hh_cb.devices[dev_handle].attr_mask = 0;
372 return HID_SUCCESS;
373 }
374
375 /*******************************************************************************
376 *
377 * Function HID_HostOpenDev
378 *
379 * Description This function is called when the user wants to initiate a
380 * connection attempt to a device.
381 *
382 * Returns void
383 *
384 ******************************************************************************/
HID_HostOpenDev(uint8_t dev_handle)385 tHID_STATUS HID_HostOpenDev(uint8_t dev_handle) {
386 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
387
388 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
389 (!hh_cb.devices[dev_handle].in_use))
390 return HID_ERR_INVALID_PARAM;
391
392 if (hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN)
393 return HID_ERR_ALREADY_CONN;
394
395 hh_cb.devices[dev_handle].conn_tries = 1;
396 return hidh_conn_initiate(dev_handle);
397 }
398
399 /*******************************************************************************
400 *
401 * Function HID_HostWriteDev
402 *
403 * Description This function is called when the host has a report to send.
404 *
405 * report_id: is only used on GET_REPORT transaction if is
406 * specified. only valid when it is non-zero.
407 *
408 * Returns void
409 *
410 ******************************************************************************/
HID_HostWriteDev(uint8_t dev_handle,uint8_t t_type,uint8_t param,uint16_t data,uint8_t report_id,BT_HDR * pbuf)411 tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param,
412 uint16_t data, uint8_t report_id, BT_HDR* pbuf) {
413 tHID_STATUS status = HID_SUCCESS;
414
415 if (!hh_cb.reg_flag) {
416 HIDH_TRACE_ERROR("HID_ERR_NOT_REGISTERED");
417 status = HID_ERR_NOT_REGISTERED;
418 }
419
420 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
421 (!hh_cb.devices[dev_handle].in_use)) {
422 HIDH_TRACE_ERROR("HID_ERR_INVALID_PARAM");
423 status = HID_ERR_INVALID_PARAM;
424 }
425
426 else if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) {
427 HIDH_TRACE_ERROR("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle);
428 status = HID_ERR_NO_CONNECTION;
429 }
430
431 if (status != HID_SUCCESS)
432 osi_free(pbuf);
433 else
434 status =
435 hidh_conn_snd_data(dev_handle, t_type, param, data, report_id, pbuf);
436
437 return status;
438 }
439
440 /*******************************************************************************
441 *
442 * Function HID_HostCloseDev
443 *
444 * Description This function disconnects the device.
445 *
446 * Returns void
447 *
448 ******************************************************************************/
HID_HostCloseDev(uint8_t dev_handle)449 tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) {
450 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
451
452 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
453 (!hh_cb.devices[dev_handle].in_use))
454 return HID_ERR_INVALID_PARAM;
455
456 if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED)
457 return HID_ERR_NO_CONNECTION;
458
459 alarm_cancel(hh_cb.devices[dev_handle].conn.process_repage_timer);
460 hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY + 1;
461 return hidh_conn_disconnect(dev_handle);
462 }
463
HID_HostSetSecurityLevel(const char serv_name[],uint8_t sec_lvl)464 tHID_STATUS HID_HostSetSecurityLevel(const char serv_name[], uint8_t sec_lvl) {
465 if (!BTM_SetSecurityLevel(false, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
466 sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
467 HID_SEC_CHN)) {
468 HIDH_TRACE_ERROR("Security Registration 1 failed");
469 return (HID_ERR_NO_RESOURCES);
470 }
471
472 if (!BTM_SetSecurityLevel(true, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
473 sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
474 HID_SEC_CHN)) {
475 HIDH_TRACE_ERROR("Security Registration 2 failed");
476 return (HID_ERR_NO_RESOURCES);
477 }
478
479 if (!BTM_SetSecurityLevel(false, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
480 BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
481 HID_NOSEC_CHN)) {
482 HIDH_TRACE_ERROR("Security Registration 3 failed");
483 return (HID_ERR_NO_RESOURCES);
484 }
485
486 if (!BTM_SetSecurityLevel(true, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
487 BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
488 HID_NOSEC_CHN)) {
489 HIDH_TRACE_ERROR("Security Registration 4 failed");
490 return (HID_ERR_NO_RESOURCES);
491 }
492
493 if (!BTM_SetSecurityLevel(true, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
494 BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
495 0)) {
496 HIDH_TRACE_ERROR("Security Registration 5 failed");
497 return (HID_ERR_NO_RESOURCES);
498 }
499
500 if (!BTM_SetSecurityLevel(false, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
501 BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
502 0)) {
503 HIDH_TRACE_ERROR("Security Registration 6 failed");
504 return (HID_ERR_NO_RESOURCES);
505 }
506
507 return (HID_SUCCESS);
508 }
509
510 /******************************************************************************
511 *
512 * Function hid_known_hid_device
513 *
514 * Description check if this device is of type HID Device
515 *
516 * Returns true if device is HID Device else false
517 *
518 ******************************************************************************/
hid_known_hid_device(const RawAddress & bd_addr)519 bool hid_known_hid_device(const RawAddress& bd_addr) {
520 uint8_t i;
521 tBTM_INQ_INFO* p_inq_info = BTM_InqDbRead(bd_addr);
522
523 if (!hh_cb.reg_flag) return false;
524
525 /* First check for class of device , if Inq DB has information about this
526 * device*/
527 if (p_inq_info != NULL) {
528 /* Check if remote major device class is of type BTM_COD_MAJOR_PERIPHERAL */
529 if ((p_inq_info->results.dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
530 BTM_COD_MAJOR_PERIPHERAL) {
531 HIDH_TRACE_DEBUG(
532 "hid_known_hid_device:dev found in InqDB & COD matches HID dev");
533 return true;
534 }
535 } else {
536 /* Look for this device in security device DB */
537 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
538 if ((p_dev_rec != NULL) &&
539 ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
540 BTM_COD_MAJOR_PERIPHERAL)) {
541 HIDH_TRACE_DEBUG(
542 "hid_known_hid_device:dev found in SecDevDB & COD matches HID dev");
543 return true;
544 }
545 }
546
547 /* Find an entry for this device in hh_cb.devices array */
548 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
549 if ((hh_cb.devices[i].in_use) && bd_addr == hh_cb.devices[i].addr)
550 return true;
551 }
552 /* Check if this device is marked as HID Device in IOP Dev */
553 HIDH_TRACE_DEBUG("hid_known_hid_device:remote is not HID device");
554 return false;
555 }
556