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 "gki.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 #if defined(HID_INITIAL_TRACE_LEVEL) 245 hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL; 246 #else 247 hh_cb.trace_level = BT_TRACE_LEVEL_NONE; 248 #endif 249 } 250 251 /******************************************************************************* 252 ** 253 ** Function HID_HostSetTraceLevel 254 ** 255 ** Description This function sets the trace level for HID Host. If called with 256 ** a value of 0xFF, it simply reads the current trace level. 257 ** 258 ** Returns the new (current) trace level 259 ** 260 *******************************************************************************/ 261 UINT8 HID_HostSetTraceLevel (UINT8 new_level) 262 { 263 if (new_level != 0xFF) 264 hh_cb.trace_level = new_level; 265 266 return (hh_cb.trace_level); 267 } 268 269 /******************************************************************************* 270 ** 271 ** Function HID_HostRegister 272 ** 273 ** Description This function registers HID-Host with lower layers 274 ** 275 ** Returns tHID_STATUS 276 ** 277 *******************************************************************************/ 278 tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback) 279 { 280 tHID_STATUS st; 281 282 if( hh_cb.reg_flag ) 283 return HID_ERR_ALREADY_REGISTERED; 284 285 if( dev_cback == NULL ) 286 return HID_ERR_INVALID_PARAM; 287 288 /* Register with L2CAP */ 289 if( (st = hidh_conn_reg()) != HID_SUCCESS ) 290 { 291 return st; 292 } 293 294 hh_cb.callback = dev_cback ; 295 hh_cb.reg_flag = TRUE; 296 297 return (HID_SUCCESS); 298 } 299 300 /******************************************************************************* 301 ** 302 ** Function HID_HostDeregister 303 ** 304 ** Description This function is called when the host is about power down. 305 ** 306 ** Returns tHID_STATUS 307 ** 308 *******************************************************************************/ 309 tHID_STATUS HID_HostDeregister(void) 310 { 311 UINT8 i; 312 313 if( !hh_cb.reg_flag ) 314 return (HID_ERR_NOT_REGISTERED); 315 316 for( i=0; i<HID_HOST_MAX_DEVICES; i++ ) 317 { 318 HID_HostRemoveDev( i ) ; 319 } 320 321 hidh_conn_dereg(); 322 hh_cb.reg_flag = FALSE; 323 324 return (HID_SUCCESS) ; 325 } 326 327 /******************************************************************************* 328 ** 329 ** Function HID_HostAddDev 330 ** 331 ** Description This is called so HID-host may manage this device. 332 ** 333 ** Returns tHID_STATUS 334 ** 335 *******************************************************************************/ 336 tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle ) 337 { 338 int i; 339 /* Find an entry for this device in hh_cb.devices array */ 340 if( !hh_cb.reg_flag ) 341 return (HID_ERR_NOT_REGISTERED); 342 343 for( i=0; i<HID_HOST_MAX_DEVICES; i++) 344 { 345 if((hh_cb.devices[i].in_use) && 346 (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN))) 347 break; 348 } 349 350 if (i== HID_HOST_MAX_DEVICES ) 351 { 352 for( i=0; i<HID_HOST_MAX_DEVICES; i++) 353 { 354 if( !hh_cb.devices[i].in_use) 355 break; 356 } 357 } 358 359 if( i==HID_HOST_MAX_DEVICES ) 360 return HID_ERR_NO_RESOURCES; 361 362 if (!hh_cb.devices[i].in_use) 363 { 364 hh_cb.devices[i].in_use = TRUE; 365 memcpy( hh_cb.devices[i].addr, addr, sizeof( BD_ADDR ) ) ; 366 hh_cb.devices[i].state = HID_DEV_NO_CONN; 367 hh_cb.devices[i].conn_tries = 0 ; 368 } 369 370 if (attr_mask != HID_ATTR_MASK_IGNORE) 371 hh_cb.devices[i].attr_mask = attr_mask; 372 373 *handle = i; 374 375 return (HID_SUCCESS); 376 } 377 378 379 /******************************************************************************* 380 ** 381 ** Function HID_HostRemoveDev 382 ** 383 ** Description This removes the device from list devices that host has to manage. 384 ** 385 ** Returns tHID_STATUS 386 ** 387 *******************************************************************************/ 388 tHID_STATUS HID_HostRemoveDev ( UINT8 dev_handle ) 389 { 390 if( !hh_cb.reg_flag ) 391 return (HID_ERR_NOT_REGISTERED); 392 393 if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) ) 394 return HID_ERR_INVALID_PARAM; 395 396 HID_HostCloseDev( dev_handle ) ; 397 hh_cb.devices[dev_handle].in_use = FALSE; 398 hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED; 399 hh_cb.devices[dev_handle].conn.ctrl_cid = hh_cb.devices[dev_handle].conn.intr_cid = 0; 400 401 return HID_SUCCESS; 402 } 403 404 /******************************************************************************* 405 ** 406 ** Function HID_HostOpenDev 407 ** 408 ** Description This function is called when the user wants to initiate a 409 ** connection attempt to a device. 410 ** 411 ** Returns void 412 ** 413 *******************************************************************************/ 414 tHID_STATUS HID_HostOpenDev ( UINT8 dev_handle ) 415 { 416 if( !hh_cb.reg_flag ) 417 return (HID_ERR_NOT_REGISTERED); 418 419 if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) ) 420 return HID_ERR_INVALID_PARAM; 421 422 if( hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN ) 423 return HID_ERR_ALREADY_CONN; 424 425 hh_cb.devices[dev_handle].conn_tries = 1; 426 return hidh_conn_initiate( dev_handle ); 427 } 428 429 /******************************************************************************* 430 ** 431 ** Function HID_HostWriteDev 432 ** 433 ** Description This function is called when the host has a report to send. 434 ** 435 ** report_id: is only used on GET_REPORT transaction if is specified. 436 ** only valid when it's a non-zero value. 437 ** 438 ** Returns void 439 ** 440 *******************************************************************************/ 441 tHID_STATUS HID_HostWriteDev( UINT8 dev_handle, UINT8 t_type, 442 UINT8 param, UINT16 data, UINT8 report_id, BT_HDR *pbuf ) 443 { 444 tHID_STATUS status = HID_SUCCESS; 445 446 if( !hh_cb.reg_flag ) 447 { 448 HIDH_TRACE_ERROR0("HID_ERR_NOT_REGISTERED"); 449 status = HID_ERR_NOT_REGISTERED; 450 } 451 452 if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) ) 453 { 454 HIDH_TRACE_ERROR0("HID_ERR_INVALID_PARAM"); 455 status = HID_ERR_INVALID_PARAM; 456 } 457 458 else if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED ) 459 { 460 HIDH_TRACE_ERROR1("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle); 461 status = HID_ERR_NO_CONNECTION; 462 } 463 464 if (status != HID_SUCCESS) 465 { 466 if (pbuf) 467 GKI_freebuf ((void *)pbuf); 468 } 469 else 470 status = hidh_conn_snd_data( dev_handle, t_type, param, data, report_id, pbuf ) ; 471 472 return status; 473 } 474 475 /******************************************************************************* 476 ** 477 ** Function HID_HostCloseDev 478 ** 479 ** Description This function disconnects the device. 480 ** 481 ** Returns void 482 ** 483 *******************************************************************************/ 484 tHID_STATUS HID_HostCloseDev( UINT8 dev_handle ) 485 { 486 if( !hh_cb.reg_flag ) 487 return (HID_ERR_NOT_REGISTERED); 488 489 if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) ) 490 return HID_ERR_INVALID_PARAM; 491 492 hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1; 493 btu_stop_timer( &(hh_cb.devices[dev_handle].conn.timer_entry) ) ; 494 495 if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED ) 496 return HID_ERR_NO_CONNECTION; 497 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_ERROR0 ("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_ERROR0 ("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_ERROR0 ("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_ERROR0 ("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_ERROR0 ("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_ERROR0 ("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_DEBUG0("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_DEBUG0("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_DEBUG0("hid_known_hid_device:remote is not HID device"); 598 return FALSE; 599 } 600