1 /* 2 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: contains ll_lt_sap_definitions specific to the ll_lt_sap module 21 */ 22 23 #include "wlan_hdd_ll_lt_sap.h" 24 #include "wlan_ll_sap_ucfg_api.h" 25 #include "osif_sync.h" 26 #include "wlan_hdd_cfg80211.h" 27 #include "os_if_ll_sap.h" 28 29 const struct nla_policy 30 wlan_hdd_ll_lt_sap_transport_switch_policy 31 [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1] = { 32 [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE] = { 33 .type = NLA_U8}, 34 [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS] = { 35 .type = NLA_U8}, 36 }; 37 38 /** 39 * __wlan_hdd_cfg80211_ll_lt_sap_transport_switch() - Request to switch the 40 * transport 41 * @wiphy: pointer to wireless wiphy structure. 42 * @wdev: pointer to wireless_dev structure. 43 * @data: Pointer to the data to be passed via vendor interface 44 * @data_len:Length of the data to be passed 45 * 46 * Return: Return the Success or Failure code. 47 */ 48 static int 49 __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy, 50 struct wireless_dev *wdev, 51 const void *data, 52 int data_len) 53 { 54 struct net_device *dev = wdev->netdev; 55 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 56 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 57 struct wlan_objmgr_vdev *vdev; 58 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1]; 59 enum qca_wlan_audio_transport_switch_type transport_switch_type; 60 enum qca_wlan_audio_transport_switch_status transport_switch_status; 61 QDF_STATUS status; 62 63 hdd_enter_dev(dev); 64 65 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 66 hdd_err("Command not allowed in FTM mode"); 67 return -EPERM; 68 } 69 70 if (wlan_hdd_validate_context(hdd_ctx)) 71 return -EINVAL; 72 73 if (hdd_validate_adapter(adapter)) 74 return -EINVAL; 75 76 if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) 77 return -EINVAL; 78 79 if (!policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc, 80 adapter->deflink->vdev_id)) { 81 hdd_err("Command not allowed on vdev %d", 82 adapter->deflink->vdev_id); 83 return -EINVAL; 84 } 85 86 if (wlan_cfg80211_nla_parse( 87 tb, QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX, 88 data, data_len, 89 wlan_hdd_ll_lt_sap_transport_switch_policy)) { 90 hdd_err("vdev %d Invalid attribute", adapter->deflink->vdev_id); 91 return -EINVAL; 92 } 93 94 if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]) { 95 hdd_err("Vdev %d attr transport switch type failed", 96 adapter->deflink->vdev_id); 97 return -EINVAL; 98 } 99 100 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc, 101 adapter->deflink->vdev_id, 102 WLAN_LL_SAP_ID); 103 if (!vdev) { 104 hdd_err("vdev %d not found", adapter->deflink->vdev_id); 105 return -EINVAL; 106 } 107 108 transport_switch_type = nla_get_u8( 109 tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]); 110 111 if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]) { 112 status = osif_ll_lt_sap_request_for_audio_transport_switch( 113 vdev, 114 transport_switch_type); 115 wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); 116 hdd_debug("Transport switch request type %d status %d vdev %d", 117 transport_switch_type, status, 118 adapter->deflink->vdev_id); 119 return qdf_status_to_os_return(status); 120 } 121 122 transport_switch_status = nla_get_u8( 123 tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]); 124 125 /* Deliver the switch response */ 126 status = osif_ll_lt_sap_deliver_audio_transport_switch_resp( 127 vdev, 128 transport_switch_type, 129 transport_switch_status); 130 131 wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); 132 133 return qdf_status_to_os_return(status); 134 } 135 136 int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy, 137 struct wireless_dev *wdev, 138 const void *data, 139 int data_len) 140 { 141 int errno; 142 struct osif_vdev_sync *vdev_sync; 143 144 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 145 if (errno) 146 return errno; 147 148 errno = __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(wiphy, wdev, 149 data, data_len); 150 151 osif_vdev_sync_op_stop(vdev_sync); 152 153 return errno; 154 } 155