/******************************************************************************* ** ** Function bta_hh_api_disable ** ** Description Perform necessary operations to disable HID host. ** ** ** Returns void ** *******************************************************************************/ void bta_hh_api_disable(void) { UINT8 xx; /* service is not enabled */ if (bta_hh_cb.p_cback == NULL) return; /* no live connection, signal DISC_CMPL_EVT directly */ if (!bta_hh_cb.cnt_num) { bta_hh_disc_cmpl(); } else /* otherwise, disconnect all live connections */ { bta_hh_cb.w4_disable = TRUE; for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) { /* send API_CLOSE event to every connected device */ if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST ) { /* disconnect all connected devices */ bta_hh_sm_execute(&bta_hh_cb.kdev[xx], BTA_HH_API_CLOSE_EVT, NULL); } } } return; }
/******************************************************************************* ** ** Function bta_hh_hdl_event ** ** Description HID host main event handling function. ** ** ** Returns void ** *******************************************************************************/ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) { UINT8 index = BTA_HH_IDX_INVALID; tBTA_HH_DEV_CB *p_cb = NULL; switch (p_msg->event) { case BTA_HH_API_ENABLE_EVT: bta_hh_api_enable((tBTA_HH_DATA *) p_msg); break; case BTA_HH_API_DISABLE_EVT: bta_hh_api_disable(); break; case BTA_HH_DISC_CMPL_EVT: /* disable complete */ bta_hh_disc_cmpl(); break; default: /* all events processed in state machine need to find corresponding CB before proceed */ if (p_msg->event == BTA_HH_API_OPEN_EVT) { index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr); } else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) { /* if add device */ if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) { index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda); } else { /* else remove device by handle */ index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific); // btla-specific ++ /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN. * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we * force the index to be IDX_INVALID */ if ((index != BTA_HH_IDX_INVALID) && (bta_hh_cb.kdev[index].in_use == FALSE)) { index = BTA_HH_IDX_INVALID; } // btla-specific -- } } else if (p_msg->event == BTA_HH_INT_OPEN_EVT) { index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr); } else { index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific); } if (index != BTA_HH_IDX_INVALID) { p_cb = &bta_hh_cb.kdev[index]; } #if BTA_HH_DEBUG APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index); #endif bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg); } return (TRUE); }
/******************************************************************************* ** ** Function bta_hh_di_sdp_cback ** ** Description SDP DI callback function. ** ** Returns void ** *******************************************************************************/ static void bta_hh_di_sdp_cback(UINT16 result) { tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur; tBTA_HH_STATUS status = BTA_HH_ERR_SDP; tSDP_DI_GET_RECORD di_rec; tHID_STATUS ret; #if BTA_HH_DEBUG APPL_TRACE_EVENT("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result); #endif /* if DI record does not exist on remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be * set to 0xffff and we will allow the connection to go through. Spec mandates that DI * record be set, but many HID devices do not set this. So for IOP purposes, we allow the * connection to go through and update the DI record to invalid DI entry.*/ if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL)) { if(result == SDP_SUCCESS && SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) { /* always update information with primary DI record */ if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) { bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0); } } else /* no DI recrod available */ { bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0); } if ((ret = HID_HostGetSDPRecord(p_cb->addr, bta_hh_cb.p_disc_db, p_bta_hh_cfg->sdp_db_size, bta_hh_sdp_cback)) == HID_SUCCESS) { status = BTA_HH_OK; } else { #if BTA_HH_DEBUG APPL_TRACE_DEBUG ("bta_hh_di_sdp_cback: HID_HostGetSDPRecord failed: Status 0x%2x", ret); #endif } } if (status != BTA_HH_OK) { utl_freebuf((void **)&bta_hh_cb.p_disc_db); /* send SDP_CMPL_EVT into state machine */ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); } return; }
/******************************************************************************* ** ** Function bta_hh_start_sdp ** ** Description Start SDP service search, and obtain necessary SDP records. ** Only one SDP service search request is allowed at the same ** time. For every BTA_HhOpen API call, do SDP first unless SDP ** has been done previously. ** ** Returns void ** *******************************************************************************/ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) { tBTA_HH_STATUS status = BTA_HH_ERR_SDP; UINT8 hdl; p_cb->sec_mask = p_data->api_conn.sec_mask; p_cb->mode = p_data->api_conn.mode; bta_hh_cb.p_cur = p_cb; #if (BTA_HH_LE_INCLUDED == TRUE) if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) { bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr); return; } #endif /* if previously virtually cabled device, skip SDP */ if (p_cb->app_id) { status = BTA_HH_OK; #if BTA_HH_DEBUG APPL_TRACE_DEBUG("bta_hh_start_sdp:: skip SDP for known devices"); #endif if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) { if (HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl) \ == HID_SUCCESS) { /* update device CB with newly register device handle */ bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL, p_cb->sub_class, p_cb->dscp_info.ssr_max_latency, p_cb->dscp_info.ssr_min_tout, p_cb->app_id); /* update cb_index[] map */ bta_hh_cb.cb_index[hdl] = p_cb->index; } else status = BTA_HH_ERR_NO_RES; } bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); return; } /* GetSDPRecord. at one time only one SDP precedure can be active */ else if (!bta_hh_cb.p_disc_db) { bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(p_bta_hh_cfg->sdp_db_size); if (bta_hh_cb.p_disc_db == NULL) { status = BTA_HH_ERR_NO_RES; } else { bta_hh_cb.p_cur = p_cb; /* do DI discovery first */ if (SDP_DiDiscover(p_data->api_conn.bd_addr, bta_hh_cb.p_disc_db, p_bta_hh_cfg->sdp_db_size, bta_hh_di_sdp_cback) != SDP_SUCCESS) { #if BTA_HH_DEBUG APPL_TRACE_DEBUG ("bta_hh_start_sdp: SDP_DiDiscover failed: \ Status 0x%2X",status); #endif status = BTA_HH_ERR_SDP; utl_freebuf((void **)&bta_hh_cb.p_disc_db); } else
/******************************************************************************* ** ** Function bta_hh_sdp_cback ** ** Description SDP callback function. ** ** Returns void ** *******************************************************************************/ static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask, tHID_DEV_SDP_INFO *sdp_rec ) { tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur; UINT8 hdl = 0; tBTA_HH_STATUS status = BTA_HH_ERR_SDP; /* make sure sdp succeeded and hh has not been disabled */ if ((result == SDP_SUCCESS) && (p_cb != NULL)) { /* security is required for the connection, add attr_mask bit*/ if (p_cb->sec_mask) attr_mask |= HID_SEC_REQUIRED; #if BTA_HH_DEBUG APPL_TRACE_EVENT("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \ attr_mask 0x%02x, handle %x", \ p_cb, result, attr_mask,p_cb->hid_handle); #endif /* check to see type of device is supported , and should not been added before */ if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) { /* if not added before */ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) { /* add device/update attr_mask information */ if(HID_HostAddDev (p_cb->addr, attr_mask, &hdl) == HID_SUCCESS) { status = BTA_HH_OK; /* update cb_index[] map */ bta_hh_cb.cb_index[hdl] = p_cb->index; } else { p_cb->app_id = 0; } } else { hdl = p_cb->hid_handle; } /* else : incoming connection after SDP should update the SDP information as well */ if (p_cb->app_id != 0) { /* update cb information with attr_mask, dscp_info etc. */ bta_hh_add_device_to_list(p_cb, hdl, attr_mask, &sdp_rec->dscp_info, sdp_rec->sub_class, sdp_rec->ssr_max_latency, sdp_rec->ssr_min_tout, p_cb->app_id); p_cb->dscp_info.ctry_code = sdp_rec->ctry_code; status = BTA_HH_OK; } } else /* type of device is not supported */ status = BTA_HH_ERR_TOD_UNSPT; } /* free disc_db when SDP is completed */ utl_freebuf((void **)&bta_hh_cb.p_disc_db); /* send SDP_CMPL_EVT into state machine */ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); return; }