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