diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 884a1eb3749c..895dccdbcf72 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1637,6 +1637,8 @@ struct hdd_context_s { /* the context that is capturing tsf */ hdd_adapter_t *cap_tsf_context; #endif + uint8_t bt_a2dp_active:1; + uint8_t bt_vo_active:1; }; /** diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 8d7b05f338c0..2d06abe1460f 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -10387,6 +10387,47 @@ static int wlan_hdd_cfg80211_set_trace_level(struct wiphy *wiphy, return ret; } + +void hdd_bt_activity_cb(void *context, uint32_t bt_activity) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context; + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (bt_activity == WLAN_COEX_EVENT_BT_A2DP_PROFILE_ADD) + hdd_ctx->bt_a2dp_active = 1; + else if (bt_activity == WLAN_COEX_EVENT_BT_A2DP_PROFILE_REMOVE) + hdd_ctx->bt_a2dp_active = 0; + else if (bt_activity == WLAN_COEX_EVENT_BT_VOICE_PROFILE_ADD) + hdd_ctx->bt_vo_active = 1; + else if (bt_activity == WLAN_COEX_EVENT_BT_VOICE_PROFILE_REMOVE) + hdd_ctx->bt_vo_active = 0; + else + return; + + hdd_info("a2dp_active:%d vo_active:%d", hdd_ctx->bt_a2dp_active, + hdd_ctx->bt_vo_active); +} + + +/** + * wlan_hdd_is_bt_in_progress() - check if bt activity is in progress + * @hdd_ctx : HDD context + * + * Return: true if BT activity is in progress else false + */ +static inline bool wlan_hdd_is_bt_in_progress(hdd_context_t *hdd_ctx) +{ + if (hdd_ctx->bt_a2dp_active || hdd_ctx->bt_vo_active) + return true; + + return false; +} + + const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { { .info.vendor_id = QCA_NL80211_VENDOR_ID, diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index c58b61b832b0..3bc3667dd5de 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -566,4 +566,13 @@ int wlan_hdd_get_adjacent_chan(uint8_t chan, bool upper); */ int wlan_hdd_merge_avoid_freqs(tHddAvoidFreqList *destFreqList, tHddAvoidFreqList *srcFreqList); + +/** + * hdd_bt_activity_cb() - callback function to receive bt activity + * @context: HDD context + * @bt_activity: specifies the kind of bt activity + * + * Return: none + */ +void hdd_bt_activity_cb(void *context, uint32_t bt_activity); #endif diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index d1d26283ac0a..740ad0c0c64d 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -9697,6 +9697,11 @@ int hdd_register_cb(hdd_context_t *hdd_ctx) if (!QDF_IS_STATUS_SUCCESS(status)) hdd_err("set congestion callback failed"); + status = sme_set_bt_activity_info_cb(hdd_ctx->hHal, + hdd_bt_activity_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set bt activity info callback failed"); + EXIT(); return ret; diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index 7c95510d1421..8f9d7cbdbb75 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -261,6 +261,7 @@ enum eWniMsgTypes { eWMI_SME_LL_STATS_IND, eWNI_SME_DFS_CAC_COMPLETE, eWNI_SME_UPDATE_CONFIG, + eWNI_SME_BT_ACTIVITY_INFO_IND, eWNI_SME_MSG_TYPES_END }; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index a735a3d6a75f..44b971586eba 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1617,4 +1617,14 @@ QDF_STATUS sme_set_chip_pwr_save_fail_cb(tHalHandle hal, void (*cb)(void *, */ int sme_cli_set_command(int vdev_id, int param_id, int sval, int vpdev); +/** + * sme_set_bt_activity_info_cb - set the callback handler for bt events + * @hal: handle returned by mac_open + * @cb: callback handler + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_bt_activity_info_cb(tHalHandle hal, + void (*cb)(void *, uint32_t profile_info)); + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 7a13c60f1734..86d8af3f8bf9 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -252,6 +252,7 @@ typedef struct tagSmeStruct { void (*stats_ext2_cb)(void *, struct sir_sme_rx_aggr_hole_ind *); void (*chip_power_save_fail_cb)(void *, struct chip_pwr_save_fail_detected_params *); + void (*bt_activity_info_cb)(void *context, uint32_t bt_activity); } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index b275929ca7c2..12bd31a6be14 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -2638,7 +2638,11 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, struct scheduler_msg *pMsg) pMsg->bodyptr); qdf_mem_free(pMsg->bodyptr); break; - + case eWNI_SME_BT_ACTIVITY_INFO_IND: + if (pMac->sme.bt_activity_info_cb) + pMac->sme.bt_activity_info_cb(pMac->hHdd, + pMsg->bodyval); + break; default: if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) @@ -16350,3 +16354,21 @@ int sme_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) { return wma_cli_set_command(vdev_id, param_id, sval, vpdev); } + +QDF_STATUS sme_set_bt_activity_info_cb(tHalHandle hal, + void (*cb)(void *, uint32_t bt_activity)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.bt_activity_info_cb = cb; + sme_release_global_lock(&mac->sme); + sme_debug("bt activity info callback set"); + } else { + sme_debug("sme_acquire_global_lock failed %d", status); + } + + return status; +} diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 35cd3b545e4a..24e3cddd2840 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1254,4 +1254,17 @@ QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id); int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf, u_int32_t len); +/** + * wma_wlan_bt_activity_evt_handler - event handler to handle bt activity + * @handle: the WMA handle + * @event: buffer with the event parameters + * @len: length of the buffer + * + * This function receives BT activity event from firmware and passes the event + * information to upper layers + * + * Return: 0 on success + */ +int wma_wlan_bt_activity_evt_handler(void *handle, uint8_t *event, + uint32_t len); #endif diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index a499028658dc..a2c15be482d9 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -5406,3 +5406,38 @@ int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf, return 0; } + +int wma_wlan_bt_activity_evt_handler(void *handle, uint8_t *event, uint32_t len) +{ + wmi_coex_bt_activity_event_fixed_param *fixed_param; + WMI_WLAN_COEX_BT_ACTIVITY_EVENTID_param_tlvs *param_buf = + (WMI_WLAN_COEX_BT_ACTIVITY_EVENTID_param_tlvs *)event; + struct scheduler_msg sme_msg = {0}; + QDF_STATUS qdf_status; + + if (!param_buf) { + WMA_LOGE(FL("Invalid BT activity event buffer")); + return -EINVAL; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + WMA_LOGE(FL("Invalid BT activity event fixed param buffer")); + return -EINVAL; + } + + WMA_LOGI(FL("Received BT activity event %u"), + fixed_param->coex_profile_evt); + + sme_msg.type = eWNI_SME_BT_ACTIVITY_INFO_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = fixed_param->coex_profile_evt; + + qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + return -EINVAL; + } + + return 0; +} diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index b7a798d09f76..8d14620ed810 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3343,6 +3343,16 @@ QDF_STATUS wma_start(void *cds_ctx) } #endif + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_WLAN_COEX_BT_ACTIVITY_EVENTID, + wma_wlan_bt_activity_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to register coex bt activity event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + end: WMA_LOGD("%s: Exit", __func__); return qdf_status;