/******************************************************************************* ** ** Function btc_a2dp_sink_enque_buf ** ** Description This function is called by the av_co to fill A2DP Sink Queue ** ** ** Returns size of the queue *******************************************************************************/ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt) { tBT_SBC_HDR *p_msg; if (btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/ return fixed_queue_length(btc_aa_snk_cb.RxSbcQ); } if (fixed_queue_length(btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) { APPL_TRACE_WARNING("Pkt dropped\n"); return fixed_queue_length(btc_aa_snk_cb.RxSbcQ); } APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + "); /* allocate and Queue this buffer */ if ((p_msg = (tBT_SBC_HDR *) osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len)) != NULL) { memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len)); p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f; APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed); fixed_queue_enqueue(btc_aa_snk_cb.RxSbcQ, p_msg); btc_a2dp_sink_data_post(BTC_A2DP_SINK_DATA_EVT); } else { /* let caller deal with a failed allocation */ APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - "); } return fixed_queue_length(btc_aa_snk_cb.RxSbcQ); }
/******************************************************************************* ** ** Function bta_ag_collision_cback ** ** Description Get notified about collision. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) { UINT16 handle; tBTA_AG_SCB *p_scb; UNUSED(status); UNUSED(app_id); /* Check if we have opening scb for the peer device. */ handle = bta_ag_idx_by_bdaddr (peer_addr); p_scb = bta_ag_scb_by_idx (handle); if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) { if (id == BTA_ID_SYS) /* ACL collision */ { APPL_TRACE_WARNING ("AG found collision (ACL) ..."); } else if (id == BTA_ID_AG) /* RFCOMM collision */ { APPL_TRACE_WARNING ("AG found collision (RFCOMM) ..."); } else { APPL_TRACE_WARNING ("AG found collision (\?\?\?) ..."); } p_scb->state = BTA_AG_INIT_ST; /* Cancel SDP if it had been started. */ if(p_scb->p_disc_db) { (void)SDP_CancelServiceSearch (p_scb->p_disc_db); bta_ag_free_db(p_scb, NULL); } /* reopen registered servers */ /* Collision may be detected before or after we close servers. */ if (bta_ag_is_server_closed (p_scb)) bta_ag_start_servers(p_scb, p_scb->reg_services); /* Start timer to han */ p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback; p_scb->colli_timer.param = (INT32)p_scb; bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER); p_scb->colli_tmr_on = TRUE; } }
/******************************************************************************* ** ** Function bta_ag_scb_alloc ** ** Description Allocate an AG service control block. ** ** ** Returns pointer to the scb, or NULL if none could be allocated. ** *******************************************************************************/ static tBTA_AG_SCB *bta_ag_scb_alloc(void) { tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; int i; for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) { if (!p_scb->in_use) { /* initialize variables */ p_scb->in_use = TRUE; p_scb->sco_idx = BTM_INVALID_SCO_INDEX; #if (BTM_WBS_INCLUDED == TRUE ) p_scb->codec_updated = FALSE; #endif /* set up timers */ p_scb->act_timer.param = (UINT32) p_scb; p_scb->act_timer.p_cback = bta_ag_timer_cback; #if (BTM_WBS_INCLUDED == TRUE) /* set eSCO mSBC setting to T2 as the preferred */ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; #endif APPL_TRACE_DEBUG("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb)); break; } } if (i == BTA_AG_NUM_SCB) { /* out of scbs */ p_scb = NULL; APPL_TRACE_WARNING("Out of ag scbs"); } return p_scb; }
/******************************************************************************* ** ** Function bta_hd_hdl_event ** ** Description HID device main event handling function. ** ** Returns void ** *******************************************************************************/ BOOLEAN bta_hd_hdl_event(BT_HDR *p_msg) { tBTA_HD_CBACK_DATA *p_data = (tBTA_HD_CBACK_DATA *) p_msg; APPL_TRACE_API("%s: p_msg->event=%d", __FUNCTION__, p_msg->event); switch (p_msg->event) { case BTA_HD_API_ENABLE_EVT: bta_hd_api_enable((tBTA_HD_DATA *) p_msg); break; case BTA_HD_API_DISABLE_EVT: if (bta_hd_cb.state == BTA_HD_CONN_ST) { APPL_TRACE_WARNING("%s: host connected, need to " "disconnect before disabling", __FUNCTION__); // unregister (and disconnect) bta_hd_cb.disable_w4_close = TRUE; bta_hd_sm_execute(BTA_HD_API_UNREGISTER_APP_EVT, (tBTA_HD_DATA *) p_msg); } else { bta_hd_api_disable(); } break; default: bta_hd_sm_execute(p_msg->event, (tBTA_HD_DATA *) p_msg); } return (TRUE); }
/******************************************************************************* ** ** Function BTA_GATTC_RegisterForNotifications ** ** Description This function is called to register for notification of a service. ** ** Parameters client_if - client interface. ** bda - target GATT server. ** p_char_id - pointer to GATT characteristic ID. ** ** Returns OK if registration succeed, otherwise failed. ** *******************************************************************************/ tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, BD_ADDR bda, tBTA_GATTC_CHAR_ID *p_char_id) { tBTA_GATTC_RCB *p_clreg; tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; UINT8 i; if (!p_char_id) { APPL_TRACE_ERROR("deregistration failed, unknow char id"); return status; } if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) { for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) { if ( p_clreg->notif_reg[i].in_use && !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id)) { APPL_TRACE_WARNING("notification already registered"); status = BTA_GATT_OK; break; } } if (status != BTA_GATT_OK) { for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) { if (!p_clreg->notif_reg[i].in_use) { memset((void *)&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); p_clreg->notif_reg[i].in_use = TRUE; memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN); p_clreg->notif_reg[i].char_id.srvc_id.is_primary = p_char_id->srvc_id.is_primary; bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.srvc_id.id, &p_char_id->srvc_id.id); bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.char_id, &p_char_id->char_id); status = BTA_GATT_OK; break; } } if (i == BTA_GATTC_NOTIF_REG_MAX) { status = BTA_GATT_NO_RESOURCES; APPL_TRACE_ERROR("Max Notification Reached, registration failed."); } } } else { APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if); } return status; }
static void bta_hf_client_send_at(tBTA_HF_CLIENT_AT_CMD cmd, char *buf, UINT16 buf_len) { if ((bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE || bta_hf_client_cb.scb.svc_conn == FALSE) && bta_hf_client_cb.scb.at_cb.hold_timer_on == FALSE) { UINT16 len; #ifdef BTA_HF_CLIENT_AT_DUMP APPL_TRACE_DEBUG("%s %.*s", __FUNCTION__, buf_len - 1, buf); #endif bta_hf_client_cb.scb.at_cb.current_cmd = cmd; /* Generate fake responses for these because they won't reliably work */ if (!service_availability && (cmd == BTA_HF_CLIENT_AT_CNUM || cmd == BTA_HF_CLIENT_AT_COPS)) { APPL_TRACE_WARNING("%s: No service, skipping %d command", __FUNCTION__, cmd); bta_hf_client_handle_ok(); return; } PORT_WriteData(bta_hf_client_cb.scb.conn_handle, buf, buf_len, &len); bta_hf_client_start_at_resp_timer(); return; } bta_hf_client_queue_at(cmd, buf, buf_len); }
/******************************************************************************* ** ** Function bta_pan_scb_alloc ** ** Description Allocate a PAN server control block. ** ** ** Returns pointer to the scb, or NULL if none could be allocated. ** *******************************************************************************/ tBTA_PAN_SCB *bta_pan_scb_alloc(void) { tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0]; int i; for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) { if (!p_scb->in_use) { p_scb->in_use = TRUE; p_scb->is_idle_timer_started = FALSE; p_scb->idle_tle.param = (UINT32) bta_pan_idle_timeout_handler; p_scb->idle_tle.data = (UINT32) p_scb; APPL_TRACE_DEBUG("bta_pan_scb_alloc: %d, scb: %p", i, p_scb); break; } } if (i == BTA_PAN_NUM_CONN) { /* out of scbs */ p_scb = NULL; APPL_TRACE_WARNING("Out of scbs"); } return p_scb; }
static void btc_a2dp_sink_ctrl_handler(BtTaskEvt_t *e) { if (e == NULL) { return; } switch (e->sig) { case BTC_MEDIA_TASK_SINK_INIT: btc_a2dp_sink_thread_init(NULL); break; case BTC_MEDIA_TASK_SINK_CLEAN_UP: btc_a2dp_sink_thread_cleanup(NULL); break; case BTC_MEDIA_AUDIO_SINK_CFG_UPDATE: btc_a2dp_sink_handle_decoder_reset(e->par); break; case BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK: btc_a2dp_sink_handle_clear_track(); break; case BTC_MEDIA_FLUSH_AA_RX: btc_a2dp_sink_rx_flush(); break; default: APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", e->sig); } if (e->par != NULL) { osi_free(e->par); } }
/******************************************************************************* ** ** Function bta_dm_pm_timer ** ** Description Process pm timer event from btm ** ** ** Returns void ** *******************************************************************************/ void bta_dm_pm_timer(tBTA_DM_MSG *p_data) { APPL_TRACE_WARNING("proc dm_pm_timer expires"); bta_dm_pm_set_mode(p_data->pm_status.bd_addr, TRUE); }
/******************************************************************************* ** ** Function bta_dm_pm_timer_cback ** ** Description Power management timer callback. ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_pm_timer_cback(void *p_tle) { tBTA_DM_PM_TIMER *p_buf; UINT8 i; APPL_TRACE_WARNING("dm_pm_timer expires"); for(i=0; i<BTA_DM_NUM_PM_TIMER; i++) { if(bta_dm_cb.pm_timer[i].in_use) { if(&bta_dm_cb.pm_timer[i].timer == (TIMER_LIST_ENT*) p_tle) { APPL_TRACE_WARNING("dm_pm_timer expires %d", i); bta_dm_cb.pm_timer[i].in_use = FALSE; break; } } } /* no more timers */ if(i==BTA_DM_NUM_PM_TIMER) { return; } if ((p_buf = (tBTA_DM_PM_TIMER *) GKI_getbuf(sizeof(tBTA_DM_PM_TIMER))) != NULL) { p_buf->hdr.event = BTA_DM_PM_TIMER_EVT; bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr); bta_sys_sendmsg(p_buf); } }
static void btc_a2dp_sink_ctrl_post(uint32_t sig, void *par) { BtTaskEvt_t *evt = (BtTaskEvt_t *)osi_malloc(sizeof(BtTaskEvt_t)); if (evt == NULL) { return; } evt->sig = sig; evt->par = par; if (xQueueSend(btc_aa_snk_ctrl_queue, &evt, portMAX_DELAY) != pdTRUE) { APPL_TRACE_WARNING("btc_aa_snk_ctrl_queue failed, sig 0x%x\n", sig); } }
static void bta_dm_pm_hid_check(BOOLEAN bScoActive) { int j; BD_ADDR peer_bdaddr; UINT8 *p = NULL; for(j=0; j<bta_dm_conn_srvcs.count ; j++) { /* check if an entry already present */ if(bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH ) { bdcpy(peer_bdaddr, bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr); APPL_TRACE_WARNING("SCO status change(Active: %d), HID state: %d", bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state); APPL_TRACE_WARNING("HID Dev address: %02x:%02x:%02x:%02x:%02x:%02x", peer_bdaddr[0], peer_bdaddr[1], peer_bdaddr[2], peer_bdaddr[3], peer_bdaddr[4], peer_bdaddr[5]); if(((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&((NULL != (p = BTM_ReadRemoteFeatures (peer_bdaddr))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p))) { if (bScoActive) { APPL_TRACE_DEBUG("bta_dm_pm_hid_check: SCO_OPEN, disabling SSR"); BTM_SetSsrParams(peer_bdaddr, 0, 0, 0); } else { APPL_TRACE_DEBUG("bta_dm_pm_hid_check: SCO_CLOSE, enabling SSR"); bta_dm_pm_ssr(peer_bdaddr); } } } } }
/******************************************************************************* ** ** Function BTA_GATTC_Disable ** ** Description This function is called to disable GATTC module ** ** Parameters None. ** ** Returns None ** *******************************************************************************/ void BTA_GATTC_Disable(void) { BT_HDR *p_buf; if (bta_sys_is_register(BTA_ID_GATTC) == FALSE) { APPL_TRACE_WARNING("GATTC Module not enabled/already disabled\n"); return; } if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) { p_buf->event = BTA_GATTC_API_DISABLE_EVT; bta_sys_sendmsg(p_buf); } bta_sys_deregister(BTA_ID_GATTC); }
static inline l2c_slot_t* find_l2c_slot_by_id(uint32_t id) { int i; if(id) { for(i = 0; i < MAX_L2C_SOCK_CHANNEL; i++) { if(l2c_slots[i].in_use && (l2c_slots[i].id == id)) { return &l2c_slots[i]; } } } APPL_TRACE_WARNING("invalid l2c slot id: %d", id); return NULL; }
/******************************************************************************* ** ** Function bta_pan_scb_by_handle ** ** Description Find scb associated with handle. ** ** ** Returns Pointer to scb or NULL if not found. ** *******************************************************************************/ tBTA_PAN_SCB *bta_pan_scb_by_handle(UINT16 handle) { tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0]; UINT8 i; for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) { if (p_scb->handle == handle) { return p_scb;; } } APPL_TRACE_WARNING("No scb for handle %d", handle); return NULL; }
/******************************************************************************* ** ** Function bta_ag_idx_by_bdaddr ** ** Description Find SCB associated with peer BD address. ** ** ** Returns Index of SCB or zero if none found. ** *******************************************************************************/ UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr) { tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; UINT16 i; if (peer_addr != NULL) { for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) { if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr)) { return (i + 1); } } } /* no scb found */ APPL_TRACE_WARNING("No ag scb for peer addr"); return 0; }
/******************************************************************************* ** ** Function bta_ag_scb_by_idx ** ** Description Given an scb index return pointer to scb. ** ** ** Returns Pointer to scb or NULL if not allocated. ** *******************************************************************************/ tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx) { tBTA_AG_SCB *p_scb; /* verify index */ if (idx > 0 && idx <= BTA_AG_NUM_SCB) { p_scb = &bta_ag_cb.scb[idx - 1]; if (!p_scb->in_use) { p_scb = NULL; APPL_TRACE_WARNING("ag scb idx %d not allocated", idx); } } else { p_scb = NULL; APPL_TRACE_DEBUG("ag scb idx %d out of range", idx); } return p_scb; }
/******************************************************************************* ** ** Function bta_hf_client_create_sco ** ** Description ** ** ** Returns void ** *******************************************************************************/ static void bta_hf_client_sco_create(BOOLEAN is_orig) { tBTM_STATUS status; UINT8 *p_bd_addr = NULL; tBTM_ESCO_PARAMS params; APPL_TRACE_DEBUG("%s %d", __FUNCTION__, is_orig); /* Make sure this sco handle is not already in use */ if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) { APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __FUNCTION__, bta_hf_client_cb.scb.sco_idx); return; } params = bta_hf_client_esco_params[1]; /* if initiating set current scb and peer bd addr */ if (is_orig) { /* Attempt to use eSCO if remote host supports HFP >= 1.5 */ if (bta_hf_client_cb.scb.peer_version >= HFP_VERSION_1_5 && !bta_hf_client_cb.scb.retry_with_sco_only) { BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, ¶ms); /* If ESCO or EDR ESCO, retry with SCO only in case of failure */ if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_HF_CLIENT_NO_EDR_ESCO)) { bta_hf_client_cb.scb.retry_with_sco_only = TRUE; APPL_TRACE_API("Setting retry_with_sco_only to TRUE"); } } else { if(bta_hf_client_cb.scb.retry_with_sco_only) APPL_TRACE_API("retrying with SCO only"); bta_hf_client_cb.scb.retry_with_sco_only = FALSE; BTM_SetEScoMode(BTM_LINK_TYPE_SCO, ¶ms); } /* tell sys to stop av if any */ bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr); } else { bta_hf_client_cb.scb.retry_with_sco_only = FALSE; } p_bd_addr = bta_hf_client_cb.scb.peer_addr; status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types, &bta_hf_client_cb.scb.sco_idx, bta_hf_client_sco_conn_cback, bta_hf_client_sco_disc_cback); if (status == BTM_CMD_STARTED && !is_orig) { if(!BTM_RegForEScoEvts(bta_hf_client_cb.scb.sco_idx, bta_hf_client_esco_connreq_cback)) APPL_TRACE_DEBUG("%s SCO registration success", __FUNCTION__); } APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x", __FUNCTION__, is_orig, bta_hf_client_cb.scb.sco_idx, status, params.packet_types); }
/******************************************************************************* ** ** Function bta_hf_client_sco_event ** ** Description Handle SCO events ** ** ** Returns void ** *******************************************************************************/ static void bta_hf_client_sco_event(UINT8 event) { APPL_TRACE_DEBUG("%s state: %d event: %d", __FUNCTION__, bta_hf_client_cb.scb.sco_state, event); switch (bta_hf_client_cb.scb.sco_state) { case BTA_HF_CLIENT_SCO_SHUTDOWN_ST: switch (event) { case BTA_HF_CLIENT_SCO_LISTEN_E: /* create sco listen connection */ bta_hf_client_sco_create(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_LISTEN_ST: switch (event) { case BTA_HF_CLIENT_SCO_LISTEN_E: /* create sco listen connection (Additional channel) */ bta_hf_client_sco_create(FALSE); break; case BTA_HF_CLIENT_SCO_OPEN_E: /* remove listening connection */ bta_hf_client_sco_remove(FALSE); /* create sco connection to peer */ bta_hf_client_sco_create(TRUE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST; break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: /* remove listening connection */ bta_hf_client_sco_remove(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST; break; case BTA_HF_CLIENT_SCO_CLOSE_E: /* remove listening connection */ /* Ignore the event. We need to keep listening SCO for the active SLC */ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event); break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: /* sco failed; create sco listen connection */ bta_hf_client_sco_create(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_OPENING_ST: switch (event) { case BTA_HF_CLIENT_SCO_CLOSE_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST; break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST; break; case BTA_HF_CLIENT_SCO_CONN_OPEN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_ST; break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: /* sco failed; create sco listen connection */ bta_hf_client_sco_create(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_OPEN_CL_ST: switch (event) { case BTA_HF_CLIENT_SCO_OPEN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST; break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST; break; case BTA_HF_CLIENT_SCO_CONN_OPEN_E: /* close sco connection */ bta_hf_client_sco_remove(TRUE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST; break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: /* sco failed; create sco listen connection */ bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_OPEN_ST: switch (event) { case BTA_HF_CLIENT_SCO_CLOSE_E: /* close sco connection if active */ if (bta_hf_client_sco_remove(TRUE)) { bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST; } break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: /* remove all listening connections */ bta_hf_client_sco_remove(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST; break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: /* peer closed sco; create sco listen connection */ bta_hf_client_sco_create(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_CLOSING_ST: switch (event) { case BTA_HF_CLIENT_SCO_OPEN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST; break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST; break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: /* peer closed sco; create sco listen connection */ bta_hf_client_sco_create(FALSE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_CLOSE_OP_ST: switch (event) { case BTA_HF_CLIENT_SCO_CLOSE_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST; break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST; break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: /* open sco connection */ bta_hf_client_sco_create(TRUE); bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", event); break; } break; case BTA_HF_CLIENT_SCO_SHUTTING_ST: switch (event) { case BTA_HF_CLIENT_SCO_CONN_OPEN_E: /* close sco connection; wait for conn close event */ bta_hf_client_sco_remove(TRUE); break; case BTA_HF_CLIENT_SCO_CONN_CLOSE_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST; break; case BTA_HF_CLIENT_SCO_SHUTDOWN_E: bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST; break; default: APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", event); break; } break; default: break; } }
static void bta_dm_pm_ssr(BD_ADDR peer_addr) { tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur; UINT8 i,j; int ssr = BTA_DM_PM_SSR0; /* go through the connected services */ for(i=0; i<bta_dm_conn_srvcs.count ; i++) { if(!bdcmp(bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr, peer_addr)) { /* p_bta_dm_pm_cfg[0].app_id is the number of entries */ for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++) { /* find the associated p_bta_dm_pm_cfg */ if((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id) && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[j].app_id == bta_dm_conn_srvcs.conn_srvc[i].app_id))) { APPL_TRACE_WARNING("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d", bta_dm_conn_srvcs.conn_srvc[i].id, bta_dm_conn_srvcs.conn_srvc[i].app_id); break; } } /* find the ssr index with the smallest max latency. */ p_spec_cur = &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr]; p_spec = &p_bta_dm_ssr_spec[ssr]; #if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) /* HH has the per connection SSR preference, already read the SSR params from BTA HH */ if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr == BTA_DM_PM_SSR_HH) { if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat, &p_spec_cur->min_rmt_to) == BTA_HH_ERR) continue; APPL_TRACE_WARNING("bta_dm_pm_ssr: Orignal Max Latency = %d, Remote Timeout = %d", p_spec_cur->max_lat, p_spec_cur->min_rmt_to); if (p_spec_cur->max_lat == BTA_HH_SSR_MAX_LATENCY_ZERO) { APPL_TRACE_WARNING("bta_dm_pm_ssr: Max latency is 0, not sending" "SSR command as device is blacklisted"); return; } else if (p_spec_cur->max_lat == BTA_HH_SSR_DISABLE_SSR) { APPL_TRACE_WARNING("bta_dm_pm_ssr: Need to disable SSR" "as device is blacklisted"); BTM_SetSsrParams (peer_addr, 0, 0, 0); return; } else if (p_spec_cur->max_lat > BTA_HH_SSR_MAX_LATENCY_OPTIMAL) { p_spec_cur->max_lat = BTA_HH_SSR_MAX_LATENCY_OPTIMAL; } APPL_TRACE_WARNING("bta_dm_pm_ssr: New Max Latency = %d", p_spec_cur->max_lat); } #endif if (p_spec_cur->max_lat < p_spec->max_lat || (ssr == BTA_DM_PM_SSR0 && p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr != BTA_DM_PM_SSR0)) { ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr; } } } p_spec = &p_bta_dm_ssr_spec[ssr]; APPL_TRACE_WARNING("bta_dm_pm_ssr:%d, lat:%d", ssr, p_spec->max_lat); if(p_spec->max_lat) { /* set the SSR parameters. */ BTM_SetSsrParams (peer_addr, p_spec->max_lat, p_spec->min_rmt_to, p_spec->min_loc_to); } }
/******************************************************************************* ** ** Function bta_dm_pm_set_mode ** ** Description Set the power mode for the device ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out ) { tBTA_DM_PM_ACTTION pm_action = BTA_DM_PM_NO_ACTION; UINT16 timeout = 0; UINT8 i,j; tBTA_DM_PM_ACTTION failed_pm = 0; tBTA_DM_PEER_DEVICE *p_peer_device = NULL; tBTA_DM_PM_ACTTION allowed_modes = 0; tBTA_DM_PM_ACTTION pref_modes = 0; tBTA_DM_PM_CFG *p_pm_cfg; tBTA_DM_PM_SPEC *p_pm_spec; tBTA_DM_PM_ACTN *p_act0, *p_act1; tBTA_DM_SRVCS *p_srvcs; if(!bta_dm_cb.device_list.count) return; /* see if any attempt to put device in low power mode failed */ p_peer_device = bta_dm_find_peer_device(peer_addr); /* if no peer device found return */ if (p_peer_device == NULL) return; failed_pm = p_peer_device->pm_mode_failed; for(i=0; i<bta_dm_conn_srvcs.count ; i++) { p_srvcs = &bta_dm_conn_srvcs.conn_srvc[i]; if(!bdcmp(p_srvcs->peer_bdaddr, peer_addr)) { /* p_bta_dm_pm_cfg[0].app_id is the number of entries */ for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++) { if((p_bta_dm_pm_cfg[j].id == p_srvcs->id) && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id))) break; } p_pm_cfg = &p_bta_dm_pm_cfg[j]; p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx]; p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0]; p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1]; APPL_TRACE_DEBUG("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d", p_srvcs->id, p_srvcs->state, j); allowed_modes |= p_pm_spec->allow_mask; /* PM actions are in the order of strictness */ /* first check if the first preference is ok */ if(!(failed_pm & p_act0->power_mode)) { pref_modes |= p_act0->power_mode; if(p_act0->power_mode > pm_action) { pm_action = p_act0->power_mode; timeout = p_act0->timeout; } } /* if first preference has already failed, try second preference */ else if(!(failed_pm & p_act1->power_mode)) { pref_modes |= p_act1->power_mode; if(p_act1->power_mode > pm_action) { pm_action = p_act1->power_mode; timeout = p_act1->timeout; } } } } if(pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) { /* some service don't like the mode */ if(!(allowed_modes & pm_action)) { /* select the other mode if its allowed and preferred, otherwise 0 which is BTA_DM_PM_NO_ACTION */ pm_action = (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes); /* no timeout needed if no action is required */ if(pm_action == BTA_DM_PM_NO_ACTION) { timeout = 0; } } } if(!timed_out && timeout) { for(i=0; i<BTA_DM_NUM_PM_TIMER; i++) { if(!bta_dm_cb.pm_timer[i].in_use) { bta_dm_cb.pm_timer[i].in_use = TRUE; bdcpy(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr); bta_dm_cb.pm_timer[i].timer.p_cback = bta_dm_pm_timer_cback; bta_sys_start_timer(&bta_dm_cb.pm_timer[i].timer, 0, timeout); APPL_TRACE_DEBUG("start dm_pm_timer:%d, %d", i, timeout); return; } } /* no more timers */ if(i==BTA_DM_NUM_PM_TIMER) { APPL_TRACE_WARNING("bta_dm_act dm_pm_timer no more"); return; } } if(pm_action == BTA_DM_PM_NO_ACTION) { } else if(pm_action == BTA_DM_PM_PARK) { p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK; bta_dm_pm_park(peer_addr); } else if(pm_action & BTA_DM_PM_SNIFF) { /* dont initiate SNIFF, if link_policy has it disabled */ if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE) { p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF; bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) ); } else { APPL_TRACE_DEBUG("bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request"); } } else if(pm_action == BTA_DM_PM_ACTIVE) { bta_dm_pm_active(peer_addr); } }
/******************************************************************************* ** ** Function bta_dm_pm_cback ** ** Description Conn change callback from sys for low power management ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) { UINT8 i,j; UINT16 policy_setting; tBTM_STATUS btm_status; tBTM_VERSION_INFO vers; UINT8 *p = NULL; #if (BTM_SSR_INCLUDED == TRUE) int index = BTA_DM_PM_SSR0; #endif tBTA_DM_PEER_DEVICE *p_dev; tACL_CONN *p_dev_rec; APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id, app_id); btm_status = BTM_ReadLocalVersion (&vers); p_dev = bta_dm_find_peer_device(peer_addr); p_dev_rec = btm_bda_to_acl(peer_addr, BT_TRANSPORT_BR_EDR); /* Disable/Enable sniff policy on the SCO link if sco Up/Down. Will be removed in 2.2*/ if ((p_dev) && ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ) { if ((btm_status == BTM_SUCCESS) && (((vers.manufacturer == LMP_COMPID_BROADCOM) && (vers.hci_version < HCI_PROTO_VERSION_2_0)) || (p_dev_rec && (p_dev_rec->lmp_version < 2)))) { if (p_dev_rec) APPL_TRACE_DEBUG("bta_dm_pm_cback:disable sniff for rmt lmp ver:%d",p_dev_rec->lmp_version); bta_dm_pm_set_sniff_policy(p_dev, (status == BTA_SYS_SCO_OPEN)); } } /* find if there is an power mode entry for the service */ for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++) { if((p_bta_dm_pm_cfg[i].id == id) && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id ))) break; } /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/ if(i> p_bta_dm_pm_cfg[0].app_id) return; /*p_dev = bta_dm_find_peer_device(peer_addr);*/ #if (BTM_SSR_INCLUDED == TRUE) /* set SSR parameters on SYS CONN OPEN */ if((BTA_SYS_CONN_OPEN == status) && p_dev && (p_dev->info & BTA_DM_DI_USE_SSR)) { index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr; } #endif /* if no action for the event */ if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_ACTION) { #if (BTM_SSR_INCLUDED == TRUE) if(BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */ #endif return; } for(j=0; j<bta_dm_conn_srvcs.count ; j++) { /* check if an entry already present */ if((bta_dm_conn_srvcs.conn_srvc[j].id == id) && (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id ) && !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) break; } /* if subsystem has no more preference on the power mode remove the cb */ if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_PREF) { if(j != bta_dm_conn_srvcs.count) { bta_dm_conn_srvcs.count--; APPL_TRACE_DEBUG("Removed power mode entry for service id = %d, count = %d", p_bta_dm_pm_cfg[i].id, bta_dm_conn_srvcs.count); for(; j<bta_dm_conn_srvcs.count ; j++) { memcpy(&bta_dm_conn_srvcs.conn_srvc[j], &bta_dm_conn_srvcs.conn_srvc[j+1], sizeof(bta_dm_conn_srvcs.conn_srvc[j])); } } else { APPL_TRACE_WARNING("bta_dm_act no entry for connected service cbs"); return; } } else if(j == bta_dm_conn_srvcs.count ) { /* check if we have more connected service that cbs */ if(bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS) { APPL_TRACE_WARNING("bta_dm_act no more connected service cbs"); return; } /* fill in a new cb */ bta_dm_conn_srvcs.conn_srvc[j].id = id; bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id; bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr); APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d", id, app_id); bta_dm_conn_srvcs.count++; bta_dm_conn_srvcs.conn_srvc[j].state = status; APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d count:%d", id, app_id, bta_dm_conn_srvcs.count); } else { /* no service is added or removed. only updating status. */ bta_dm_conn_srvcs.conn_srvc[j].state = status; } /* stop timer */ bta_dm_pm_stop_timer(peer_addr); if(p_dev) { p_dev->pm_mode_attempted = 0; p_dev->pm_mode_failed = 0; } #if (BTM_SSR_INCLUDED == TRUE) if(p_bta_dm_ssr_spec[index].max_lat #if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) || index == BTA_DM_PM_SSR_HH #endif ) { /* If HID connection open is received and SCO is already active. This will handle the case where HID connects when SCO already active */ if ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) { APPL_TRACE_DEBUG("bta_dm_pm_cback: SCO is Active, disabling SSR on HID link") APPL_TRACE_WARNING("HID Dev address: %02x:%02x:%02x:%02x:%02x:%02x", peer_addr[0], peer_addr[1], peer_addr[2], peer_addr[3], peer_addr[4], peer_addr[5]); BTM_SetSsrParams(peer_addr, 0, 0, 0); } else { bta_dm_pm_ssr(peer_addr); } } else { if( ((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && ((NULL != (p = BTM_ReadRemoteFeatures (peer_addr))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && (index == BTA_DM_PM_SSR0) ) { if (status == BTA_SYS_SCO_OPEN) { APPL_TRACE_DEBUG("bta_dm_pm_cback: SCO is open, reset SSR to zero"); BTM_SetSsrParams (peer_addr, 0,0,0 ); } else if (status == BTA_SYS_SCO_CLOSE) { APPL_TRACE_DEBUG("bta_dm_pm_cback: SCO is close, back to old SSR"); bta_dm_pm_ssr(peer_addr); } } } /* If SCO up/down event is received, then enable/disable SSR on active HID link */ if (btm_status == BTM_SUCCESS && (status == BTA_SYS_SCO_OPEN || status == BTA_SYS_SCO_CLOSE)) { BOOLEAN bScoActive = (status == BTA_SYS_SCO_OPEN); APPL_TRACE_DEBUG("bta_dm_pm_cback: bta_dm_pm_hid_check with bScoActive = %d", bScoActive); bta_dm_pm_hid_check(bScoActive); } #endif bta_dm_pm_set_mode(peer_addr, FALSE); }