Forráskód Böngészése

qcacld-3.0: Handle vendor command and events for audio transport switch

Based on new requirement, add changes to send the vendor event
send audio transport switch request and also add changes to process
the response received as a vendor command.

Change-Id: I4b8804c9021ea8807ca785f81f3df431690029fb
CRs-Fixed: 3626954
Ashish Kumar Dhanotiya 1 éve
szülő
commit
1c37983a22

+ 218 - 13
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c

@@ -404,6 +404,26 @@ ll_lt_sap_find_first_valid_bs_non_wlan_req(struct bearer_switch_info *bs_ctx)
 	return NULL;
 }
 
+/*
+ * ll_lt_sap_send_bs_req_to_userspace() - Send bearer switch request to user
+ * space
+ * @vdev: ll_lt sap vdev
+ *
+ * API to send bearer switch request to userspace
+ *
+ * Return: None
+ */
+static void
+ll_lt_sap_send_bs_req_to_userspace(struct wlan_objmgr_vdev *vdev,
+				   enum bearer_switch_req_type req_type)
+{
+	struct ll_sap_ops *osif_cbk;
+
+	osif_cbk = ll_sap_get_osif_cbk();
+	if (osif_cbk && osif_cbk->ll_sap_send_audio_transport_switch_req_cb)
+		osif_cbk->ll_sap_send_audio_transport_switch_req_cb(vdev,
+								    req_type);
+}
 /**
  * ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state() - API to handle bearer switch
  * to wlan in non-wlan state.
@@ -439,9 +459,7 @@ static void ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state(
 
 	ll_lt_sap_cache_bs_request(bs_ctx, bs_req);
 
-	/*
-	 * Todo, Send bearer switch request to userspace
-	 */
+	ll_lt_sap_send_bs_req_to_userspace(bs_ctx->vdev, bs_req->req_type);
 
 	status = qdf_mc_timer_start(&bs_ctx->bs_request_timer,
 				    BEARER_SWITCH_TIMEOUT);
@@ -484,9 +502,8 @@ ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state(
 	if (QDF_IS_STATUS_SUCCESS(bs_ctx->last_status))
 		return ll_lt_sap_invoke_req_callback(bs_ctx, bs_req,
 						     QDF_STATUS_E_ALREADY);
-	/*
-	 * Todo, Send bearer switch request to userspace
-	 */
+
+	ll_lt_sap_send_bs_req_to_userspace(bs_ctx->vdev, bs_req->req_type);
 
 	status = qdf_mc_timer_start(&bs_ctx->bs_request_timer,
 				    BEARER_SWITCH_TIMEOUT);
@@ -750,7 +767,6 @@ static void ll_lt_sap_handle_bs_to_wlan_in_wlan_state(
 				struct bearer_switch_info *bs_ctx,
 				struct wlan_bearer_switch_request *bs_req)
 {
-
 	ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, QDF_STATUS_E_ALREADY);
 }
 
@@ -847,12 +863,6 @@ ll_lt_sap_handle_bs_to_non_wlan_in_wlan_req_state(
 					  bs_req->source);
 
 	ll_lt_sap_cache_bs_request(bs_ctx, bs_req);
-
-	/*
-	 * Todo, upon receiving response for wlan request, deliver event
-	 * WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED from the vendor command
-	 * path
-	 */
 }
 
 /**
@@ -1473,3 +1483,198 @@ rel_ref:
 
 	return status;
 }
+
+QDF_STATUS ll_lt_sap_switch_bearer_to_ble(
+				struct wlan_objmgr_psoc *psoc,
+				struct wlan_bearer_switch_request *bs_request)
+{
+	return bs_sm_deliver_event(psoc, WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN,
+				   sizeof(*bs_request), bs_request);
+}
+
+QDF_STATUS ll_lt_sap_request_for_audio_transport_switch(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type)
+{
+	struct ll_sap_vdev_priv_obj *ll_sap_obj;
+	struct bearer_switch_info *bearer_switch_ctx;
+
+	ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev);
+
+	if (!ll_sap_obj) {
+		ll_sap_err("BS_SM vdev %d ll_sap obj null",
+			   wlan_vdev_get_id(vdev));
+		return QDF_STATUS_E_INVAL;
+	}
+	bearer_switch_ctx = ll_sap_obj->bearer_switch_ctx;
+	if (!bearer_switch_ctx)
+		return QDF_STATUS_E_INVAL;
+
+	/*
+	 * Request to switch to non-wlan can always be acceptes so,
+	 * always return success
+	 */
+	if (req_type == WLAN_BS_REQ_TO_NON_WLAN) {
+		ll_sap_debug("BS_SM vdev %d WLAN_BS_REQ_TO_NON_WLAN accepted",
+			     wlan_vdev_get_id(vdev));
+		return QDF_STATUS_SUCCESS;
+	} else if (req_type == WLAN_BS_REQ_TO_WLAN) {
+		/*
+		 * Total_ref_count zero indicates that no module wants to stay
+		 * in non-wlan mode so this request can be accepted
+		 */
+		if (!qdf_atomic_read(&bearer_switch_ctx->total_ref_count)) {
+			ll_sap_debug("BS_SM vdev %d WLAN_BS_REQ_TO_WLAN accepted",
+				     wlan_vdev_get_id(vdev));
+			return QDF_STATUS_SUCCESS;
+		}
+		ll_sap_debug("BS_SM vdev %d WLAN_BS_REQ_TO_WLAN rejected",
+			     wlan_vdev_get_id(vdev));
+
+		return QDF_STATUS_E_FAILURE;
+		}
+	} else {
+		ll_sap_err("BS_SM vdev %d Invalid audio transport type %d",
+			   req_type);
+	}
+
+	return QDF_STATUS_E_INVAL;
+}
+
+/**
+ * ll_lt_sap_deliver_wlan_audio_transport_switch_resp() - Deliver wlan
+ * audio transport switch response to BS_SM
+ * @vdev: ll_lt sap vdev
+ * @status: Status of the request
+ *
+ * Return: None
+ */
+static void ll_lt_sap_deliver_wlan_audio_transport_switch_resp(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_status status)
+{
+	struct wlan_bearer_switch_request *bs_request;
+	struct ll_sap_vdev_priv_obj *ll_sap_obj;
+	struct bearer_switch_info *bs_ctx;
+
+	ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev);
+
+	if (!ll_sap_obj) {
+		ll_sap_err("BS_SM vdev %d ll_sap obj null",
+			   wlan_vdev_get_id(vdev));
+		return;
+	}
+
+	bs_ctx = ll_sap_obj->bearer_switch_ctx;
+	if (!bs_ctx)
+		return;
+
+	bs_request = ll_lt_sap_find_first_valid_bs_wlan_req(bs_ctx);
+
+	/*
+	 * If bs_request is cached in the BS_SM, it means this is a response
+	 * to the host driver's request of bearer switch so deliver the event
+	 * to the BS_SM
+	 */
+	if (bs_request) {
+		if (status == WLAN_BS_STATUS_COMPLETED)
+			bs_sm_deliver_event(
+					wlan_vdev_get_psoc(vdev),
+					WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED,
+					sizeof(*bs_request), bs_request);
+		else if (status == WLAN_BS_STATUS_REJECTED)
+			bs_sm_deliver_event(
+					wlan_vdev_get_psoc(vdev),
+					WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE,
+					sizeof(*bs_request), bs_request);
+		else
+			ll_sap_err("BS_SM vdev %d Invalid BS status %d",
+				   wlan_vdev_get_id(vdev), status);
+		return;
+	}
+
+	/*
+	 * If there is no cached request in BS_SM, it means that some other
+	 * module has performed the bearer switch and it is not a response of
+	 * the wlan bearer switch request, so just update the current state of
+	 * the state machine
+	 */
+	bs_sm_state_update(bs_ctx, BEARER_WLAN);
+}
+
+/**
+ * ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp() - Deliver non wlan
+ * audio transport switch response to BS_SM
+ * @vdev: ll_lt sap vdev
+ * @status: Status of the request
+ *
+ * Return: None
+ */
+static void ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_status status)
+{
+	struct wlan_bearer_switch_request *bs_request;
+	struct ll_sap_vdev_priv_obj *ll_sap_obj;
+	struct bearer_switch_info *bs_ctx;
+
+	ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev);
+
+	if (!ll_sap_obj) {
+		ll_sap_err("BS_SM vdev %d ll_sap obj null",
+			   wlan_vdev_get_id(vdev));
+		return;
+	}
+
+	bs_ctx = ll_sap_obj->bearer_switch_ctx;
+	if (!bs_ctx)
+		return;
+
+	bs_request = ll_lt_sap_find_first_valid_bs_non_wlan_req(bs_ctx);
+
+	/*
+	 * If bs_request is cached in the BS_SM, it means this is a response
+	 * to the host driver's request of bearer switch so deliver the event
+	 * to the BS_SM
+	 */
+	if (bs_request) {
+		if (status == WLAN_BS_STATUS_COMPLETED)
+			bs_sm_deliver_event(
+				wlan_vdev_get_psoc(vdev),
+				WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED,
+				sizeof(*bs_request), bs_request);
+		else if (status == WLAN_BS_STATUS_REJECTED)
+			bs_sm_deliver_event(
+				wlan_vdev_get_psoc(vdev),
+				WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_FAILURE,
+				sizeof(*bs_request), bs_request);
+		else
+			ll_sap_err("BS_SM vdev %d Invalid BS status %d",
+				   wlan_vdev_get_id(vdev), status);
+		return;
+	}
+
+	/*
+	 * If there is no cached request in BS_SM, it means that some other
+	 * module has performed the bearer switch and it is not a response of
+	 * the wlan bearer switch request, so just update the current state of
+	 * the state machine
+	 */
+	bs_sm_state_update(bs_ctx, BEARER_NON_WLAN);
+}
+
+void ll_lt_sap_deliver_audio_transport_switch_resp(
+			struct wlan_objmgr_vdev *vdev,
+			enum bearer_switch_req_type req_type,
+			enum bearer_switch_status status)
+{
+	if (req_type == WLAN_BS_REQ_TO_NON_WLAN)
+		ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp(
+								vdev,
+								status);
+
+	if (req_type == WLAN_BS_REQ_TO_WLAN)
+		ll_lt_sap_deliver_wlan_audio_transport_switch_resp(
+								vdev,
+								status);
+}

+ 36 - 0
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.h

@@ -260,4 +260,40 @@ bool __ll_lt_sap_is_bs_ctx_valid(struct bearer_switch_info *bs_ctx,
 bool __ll_lt_sap_is_bs_req_valid(struct wlan_bearer_switch_request *bs_req,
 				 const char *func);
 
+/**
+ * ll_lt_sap_switch_bearer_to_ble() - Switch audio transport to BLE
+ * @psoc: Pointer to psoc
+ * @bs_request: Pointer to bearer switch request
+ * Return: QDF_STATUS_SUCCESS on successful bearer switch else failure
+ */
+QDF_STATUS
+ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc,
+			       struct wlan_bearer_switch_request *bs_request);
+
+/**
+ * ll_lt_sap_request_for_audio_transport_switch() - Handls audio transport
+ * switch request from userspace
+ * @vdev: Vdev on which the request is received
+ * @req_type: requested transport switch type
+ *
+ * Return: True/False
+ */
+QDF_STATUS
+ll_lt_sap_request_for_audio_transport_switch(struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type);
+
+/**
+ * ll_lt_sap_deliver_audio_transport_switch_resp() - Deliver audio
+ * transport switch response
+ * @vdev: Vdev on which the request is received
+ * @req_type: Transport switch type for which the response is received
+ * @status: Status of the response
+ *
+ * Return: None
+ */
+void ll_lt_sap_deliver_audio_transport_switch_resp(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status);
+
 #endif /* _WLAN_LL_LT_SAP_BEARER_SWITCH_H_ */

+ 1 - 2
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c

@@ -146,8 +146,7 @@ QDF_STATUS ll_lt_sap_deinit(struct wlan_objmgr_vdev *vdev)
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS ll_lt_sap_switch_bearer_to_ble(
-				struct wlan_objmgr_psoc *psoc,
+QDF_STATUS ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc,
 				struct wlan_bearer_switch_request *bs_request)
 {
 	return bs_sm_deliver_event(psoc, WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN,

+ 5 - 0
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c

@@ -233,3 +233,8 @@ void ll_sap_unregister_os_if_cb(void)
 {
 	global_ll_sap_ops = NULL;
 }
+
+struct ll_sap_ops *ll_sap_get_osif_cbk(void)
+{
+	return global_ll_sap_ops;
+}

+ 8 - 0
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h

@@ -94,4 +94,12 @@ void ll_sap_register_os_if_cb(struct ll_sap_ops *ll_sap_global_ops);
  * Return: None
  */
 void ll_sap_unregister_os_if_cb(void);
+
+/**
+ * ll_sap_get_osif_cbk() - API to get ll_sap osif callbacks
+ *
+ * Return: global ll_sap osif callback
+ */
+struct ll_sap_ops *ll_sap_get_osif_cbk(void);
+
 #endif /* _WLAN_LL_SAP_MAIN_H_ */

+ 15 - 1
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h

@@ -34,10 +34,24 @@ typedef uint32_t wlan_bs_req_id;
  * enum bearer_switch_req_type: Bearer switch request type
  * @WLAN_BS_REQ_TO_NON_WLAN: Bearer switch request to non-wlan
  * @WLAN_BS_REQ_TO_WLAN: Bearer switch request to wlan
+ * @WLAN_BS_REQ_INVALID: Invalid bearer switch request
  */
 enum bearer_switch_req_type {
 	WLAN_BS_REQ_TO_NON_WLAN = 0,
 	WLAN_BS_REQ_TO_WLAN = 1,
+	WLAN_BS_REQ_INVALID,
+};
+
+/**
+ * enum bearer_switch_status: Bearer switch status
+ * @WLAN_BS_STATUS_REJECTED: Bearer switch request rejected
+ * @WLAN_BS_STATUS_COMPLETED: Bearer switch request completed
+ * @WLAN_BS_STATUS_INVALID: Invalid bearer switch request
+ */
+enum bearer_switch_status {
+	WLAN_BS_STATUS_REJECTED = 0,
+	WLAN_BS_STATUS_COMPLETED = 1,
+	WLAN_BS_STATUS_INVALID,
 };
 
 /**
@@ -58,7 +72,7 @@ enum bearer_switch_req_source {
  * typedef bearer_switch_requester_cb() - Callback function, which will
  * be invoked with the bearer switch request status.
  * @psoc: Psoc pointer
- * @vdev_id: Vdev id of the requester
+ * @vdev_id: vdev id of the requester
  * @request_id: Request ID
  * @status: Status of the bearer switch request
  * @req_value: Request value for the bearer switch request

+ 25 - 0
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h

@@ -50,13 +50,29 @@ bool ucfg_is_ll_lt_sap_supported(void);
 /**
  * ucfg_ll_lt_sap_request_for_audio_transport_switch() - Request to switch the
  * audio transport medium
+ * @vdev: Vdev on which the request is received
  * @req_type: Requested transport switch type
  *
  * Return: Accepted/Rejected
  */
 QDF_STATUS ucfg_ll_lt_sap_request_for_audio_transport_switch(
+					struct wlan_objmgr_vdev *vdev,
 					enum bearer_switch_req_type req_type);
 
+/**
+ * ucfg_ll_lt_sap_deliver_audio_transport_switch_resp() - Deliver audio
+ * transport switch response
+ * @vdev: Vdev on which the request is received
+ * @req_type: Transport switch type for which the response is received
+ * @status: Status of the response
+ *
+ * Return: None
+ */
+void ucfg_ll_lt_sap_deliver_audio_transport_switch_resp(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status);
+
 /**
  * ucfg_ll_sap_register_cb() - Register ll_sap osif callbacks
  * @ll_sap_global_ops: Ops which needs to be registered
@@ -90,11 +106,20 @@ static inline bool ucfg_is_ll_lt_sap_supported(void)
 
 static inline QDF_STATUS
 ucfg_ll_lt_sap_request_for_audio_transport_switch(
+					struct wlan_objmgr_vdev *vdev,
 					enum bearer_switch_req_type req_type)
 {
 	return QDF_STATUS_E_INVAL;
 }
 
+static inline void
+ucfg_ll_lt_sap_deliver_audio_transport_switch_resp(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status)
+{
+}
+
 static inline void ucfg_ll_sap_register_cb(struct ll_sap_ops *ll_sap_global_ops)
 {
 }

+ 12 - 2
components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c

@@ -21,6 +21,7 @@
  */
 #include "../../core/src/wlan_ll_sap_main.h"
 #include "../../core/src/wlan_ll_lt_sap_main.h"
+#include "../../core/src/wlan_ll_lt_sap_bearer_switch.h"
 #include <wlan_ll_sap_ucfg_api.h>
 
 QDF_STATUS ucfg_ll_sap_init(void)
@@ -39,9 +40,19 @@ bool ucfg_is_ll_lt_sap_supported(void)
 }
 
 QDF_STATUS ucfg_ll_lt_sap_request_for_audio_transport_switch(
+					struct wlan_objmgr_vdev *vdev,
 					enum bearer_switch_req_type req_type)
 {
-	return ll_lt_sap_request_for_audio_transport_switch(req_type);
+	return ll_lt_sap_request_for_audio_transport_switch(vdev, req_type);
+}
+
+void ucfg_ll_lt_sap_deliver_audio_transport_switch_resp(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status)
+{
+	ll_lt_sap_deliver_audio_transport_switch_resp(vdev, req_type,
+						      status);
 }
 
 void ucfg_ll_sap_register_cb(struct ll_sap_ops *ll_sap_global_ops)
@@ -53,4 +64,3 @@ void ucfg_ll_sap_unregister_cb(void)
 {
 	ll_sap_unregister_os_if_cb();
 }
-

+ 39 - 18
core/hdd/src/wlan_hdd_ll_lt_sap.c

@@ -54,6 +54,7 @@ __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
 	struct net_device *dev = wdev->netdev;
 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	struct wlan_objmgr_vdev *vdev;
 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1];
 	enum qca_wlan_audio_transport_switch_type transport_switch_type;
 	enum qca_wlan_audio_transport_switch_status transport_switch_status;
@@ -66,50 +67,70 @@ __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,
 		return -EPERM;
 	}
 
-	if (0 != wlan_hdd_validate_context(hdd_ctx))
+	if (wlan_hdd_validate_context(hdd_ctx))
 		return -EINVAL;
 
-	if (!adapter)
+	if (hdd_validate_adapter(adapter))
 		return -EINVAL;
 
+	if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id))
+		return -EINVAL;
+
+	if (!policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc,
+					  adapter->deflink->vdev_id)) {
+		hdd_err("Command not allowed on vdev %d",
+			adapter->deflink->vdev_id);
+		return -EINVAL;
+	}
+
 	if (wlan_cfg80211_nla_parse(
 			tb, QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX,
 			data, data_len,
 			wlan_hdd_ll_lt_sap_transport_switch_policy)) {
-		hdd_err("Invalid attribute");
+		hdd_err("vdev %d Invalid attribute", adapter->deflink->vdev_id);
 		return -EINVAL;
 	}
 
 	if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]) {
-		hdd_err("attr transport switch type failed");
+		hdd_err("Vdev %d attr transport switch type failed",
+			adapter->deflink->vdev_id);
 		return -EINVAL;
 	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc,
+						    adapter->deflink->vdev_id,
+						    WLAN_LL_SAP_ID);
+	if (!vdev) {
+		hdd_err("vdev %d not found", adapter->deflink->vdev_id);
+		return -EINVAL;
+	}
+
 	transport_switch_type = nla_get_u8(
 			tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]);
 
 	if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]) {
 		status = osif_ll_lt_sap_request_for_audio_transport_switch(
-							transport_switch_type);
-		hdd_debug("Transport switch request type %d status %d",
-			  transport_switch_type, status);
+						vdev,
+						transport_switch_type);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID);
+		hdd_debug("Transport switch request type %d status %d vdev %d",
+			  transport_switch_type, status,
+			  adapter->deflink->vdev_id);
 		return qdf_status_to_os_return(status);
 	}
 
 	transport_switch_status = nla_get_u8(
 			tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]);
 
-	if (transport_switch_status ==
-		QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED) {
-		hdd_debug("Transport switch request completed");
-		return 0;
-	} else if (transport_switch_status ==
-		QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED) {
-		hdd_debug("Transport switch request rejected");
-		return 0;
-	}
+	/* Deliver the switch response */
+	status = osif_ll_lt_sap_deliver_audio_transport_switch_resp(
+						vdev,
+						transport_switch_type,
+						transport_switch_status);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID);
 
-	hdd_err("Invalid transport switch status");
-	return -EINVAL;
+	return qdf_status_to_os_return(status);
 }
 
 int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy,

+ 35 - 0
os_if/mlme/sap/ll_sap/inc/os_if_ll_sap.h

@@ -23,6 +23,7 @@
 
 #include "qdf_types.h"
 #include "qca_vendor.h"
+#include "wlan_objmgr_vdev_obj.h"
 
 #ifdef WLAN_FEATURE_LL_LT_SAP
 
@@ -40,9 +41,32 @@ QDF_STATUS osif_ll_sap_register_cb(void);
  */
 void osif_ll_sap_unregister_cb(void);
 
+/**
+ * osif_ll_lt_sap_request_for_audio_transport_switch() - Userspace request for
+ * the audio transport switch
+ * @vdev: Vdev on which the request is received
+ * @req_type: Type of the request
+ *
+ * Return: QDF_STATUS
+ */
 QDF_STATUS osif_ll_lt_sap_request_for_audio_transport_switch(
+			struct wlan_objmgr_vdev *vdev,
 			enum qca_wlan_audio_transport_switch_type req_type);
 
+/**
+ * osif_ll_lt_sap_deliver_audio_transport_switch_resp() - Deliver userspace
+ * response for the audio transport switch request to BS_SM
+ * @vdev: Vdev on which the response is received
+ * @req_type: Type of the request
+ * @status: status of the response
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS osif_ll_lt_sap_deliver_audio_transport_switch_resp(
+			struct wlan_objmgr_vdev *vdev,
+			enum qca_wlan_audio_transport_switch_type req_type,
+			enum qca_wlan_audio_transport_switch_status status);
+
 #else
 static inline QDF_STATUS osif_ll_sap_register_cb(void)
 {
@@ -53,9 +77,20 @@ static inline void osif_ll_sap_unregister_cb(void) {}
 
 static inline QDF_STATUS
 osif_ll_lt_sap_request_for_audio_transport_switch(
+			struct wlan_objmgr_vdev *vdev,
 			enum qca_wlan_audio_transport_switch_type req_type)
 {
 	return QDF_STATUS_E_INVAL;
 }
+
+static inline QDF_STATUS
+osif_ll_lt_sap_deliver_audio_transport_switch_resp(
+			struct wlan_objmgr_vdev *vdev,
+			enum qca_wlan_audio_transport_switch_type req_type,
+			enum qca_wlan_audio_transport_switch_status status)
+{
+	return QDF_STATUS_E_INVAL;
+}
+
 #endif /* WLAN_FEATURE_LL_LT_SAP */
 #endif /* __OS_IF_LL_SAP_H__*/

+ 64 - 0
os_if/mlme/sap/ll_sap/src/os_if_ll_sap.c

@@ -25,6 +25,8 @@
 #include "wlan_cfg80211.h"
 #include "wlan_osif_priv.h"
 
+#define WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_INVALID 0xFFFF
+
 /**
  * osif_convert_audio_transport_switch_req_type_to_qca_type() - Convert
  * audio transport switch request type to qca audio transport switch req type
@@ -41,6 +43,9 @@ osif_convert_audio_transport_switch_req_type_to_qca_type
 		return QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN;
 	case WLAN_BS_REQ_TO_WLAN:
 		return QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN;
+	default:
+		osif_err("Invalid audio transport switch type");
+		return WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_INVALID;
 	}
 }
 
@@ -60,6 +65,30 @@ osif_convert_audio_transport_switch_req_type_from_qca_type
 		return WLAN_BS_REQ_TO_NON_WLAN;
 	case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN:
 		return WLAN_BS_REQ_TO_WLAN;
+	default:
+		osif_err("Invalid %d req type", req_type);
+		return WLAN_BS_REQ_INVALID;
+	}
+}
+
+/**
+ * osif_convert_audio_transport_switch_status_type_from_qca_type() - Convert
+ * audio transport switch status from qca audio transport switch status type
+ * @status:    audio transport switch status.
+ *
+ * Return:   enum bearer_switch_status
+ */
+static enum bearer_switch_status
+osif_convert_audio_transport_switch_status_type_from_qca_type
+			(enum qca_wlan_audio_transport_switch_status status)
+{
+	switch (status) {
+	case  QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED:
+		return WLAN_BS_STATUS_REJECTED;
+	case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED:
+		return WLAN_BS_STATUS_COMPLETED;
+	default:
+		return WLAN_BS_REQ_INVALID;
 	}
 }
 
@@ -126,13 +155,48 @@ static void wlan_osif_send_audio_transport_switch_req_event(
 }
 
 QDF_STATUS osif_ll_lt_sap_request_for_audio_transport_switch(
+			struct wlan_objmgr_vdev *vdev,
 			enum qca_wlan_audio_transport_switch_type req_type)
 {
 	return ucfg_ll_lt_sap_request_for_audio_transport_switch(
+		vdev,
 		osif_convert_audio_transport_switch_req_type_from_qca_type(
 								req_type));
 }
 
+QDF_STATUS osif_ll_lt_sap_deliver_audio_transport_switch_resp(
+			struct wlan_objmgr_vdev *vdev,
+			enum qca_wlan_audio_transport_switch_type req_type,
+			enum qca_wlan_audio_transport_switch_status status)
+{
+	static enum bearer_switch_status bs_status;
+	enum bearer_switch_req_type bs_req_type;
+	uint8_t vdev_id = wlan_vdev_get_id(vdev);
+
+	if (status == QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED) {
+		osif_nofl_debug("vdev %d Transport switch request %d completed",
+				vdev_id, req_type);
+	} else if (status == QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED) {
+		osif_nofl_debug("vdev %d Transport switch request %d rejected",
+				vdev_id, req_type);
+	} else {
+		osif_err("vdev %d Invalid transport switch status %d", vdev_id,
+			 status);
+		return QDF_STATUS_E_INVAL;
+	}
+	bs_status =
+		osif_convert_audio_transport_switch_status_type_from_qca_type(
+									status);
+	bs_req_type =
+		osif_convert_audio_transport_switch_req_type_from_qca_type(
+								req_type);
+
+	ucfg_ll_lt_sap_deliver_audio_transport_switch_resp(vdev, bs_req_type,
+							   bs_status);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 static struct ll_sap_ops ll_sap_global_ops = {
 	.ll_sap_send_audio_transport_switch_req_cb =
 		wlan_osif_send_audio_transport_switch_req_event,