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