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 any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /** 18 * DOC: contains ll_sap definitions specific to the ll_lt_sap module 19 */ 20 21 #include "os_if_ll_sap.h" 22 #include "wlan_ll_sap_public_structs.h" 23 #include "wlan_ll_sap_ucfg_api.h" 24 #include "wlan_objmgr_vdev_obj.h" 25 #include "wlan_cfg80211.h" 26 #include "wlan_osif_priv.h" 27 28 #define WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_INVALID 0xFFFF 29 30 /** 31 * osif_convert_audio_transport_switch_req_type_to_qca_type() - Convert 32 * audio transport switch request type to qca audio transport switch req type 33 * @req_type: Request type 34 * 35 * Return: enum qca_wlan_audio_transport_switch_type 36 */ 37 static enum qca_wlan_audio_transport_switch_type 38 osif_convert_audio_transport_switch_req_type_to_qca_type 39 (enum bearer_switch_req_type req_type) 40 { 41 switch (req_type) { 42 case WLAN_BS_REQ_TO_NON_WLAN: 43 return QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN; 44 case WLAN_BS_REQ_TO_WLAN: 45 return QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN; 46 default: 47 osif_err("Invalid audio transport switch type"); 48 return WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_INVALID; 49 } 50 } 51 52 /** 53 * osif_convert_audio_transport_switch_req_type_from_qca_type() - Convert 54 * audio transport switch request type from qca audio transport switch req type 55 * @req_type: Request type. 56 * 57 * Return: enum bearer_switch_req_type 58 */ 59 static enum bearer_switch_req_type 60 osif_convert_audio_transport_switch_req_type_from_qca_type 61 (enum qca_wlan_audio_transport_switch_type req_type) 62 { 63 switch (req_type) { 64 case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN: 65 return WLAN_BS_REQ_TO_NON_WLAN; 66 case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN: 67 return WLAN_BS_REQ_TO_WLAN; 68 default: 69 osif_err("Invalid %d req type", req_type); 70 return WLAN_BS_REQ_INVALID; 71 } 72 } 73 74 /** 75 * osif_convert_audio_transport_switch_status_type_from_qca_type() - Convert 76 * audio transport switch status from qca audio transport switch status type 77 * @status: audio transport switch status. 78 * 79 * Return: enum bearer_switch_status 80 */ 81 static enum bearer_switch_status 82 osif_convert_audio_transport_switch_status_type_from_qca_type 83 (enum qca_wlan_audio_transport_switch_status status) 84 { 85 switch (status) { 86 case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED: 87 return WLAN_BS_STATUS_REJECTED; 88 case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED: 89 return WLAN_BS_STATUS_COMPLETED; 90 default: 91 return WLAN_BS_STATUS_INVALID; 92 } 93 } 94 95 /** 96 * wlan_osif_send_audio_transport_switch_req() - Send audio transport 97 * switch request 98 * @vdev: pointer to vdev structure. 99 * @req_type: Request type. 100 * 101 * Return: None. 102 */ 103 static void 104 wlan_osif_send_audio_transport_switch_req(struct wlan_objmgr_vdev *vdev, 105 enum bearer_switch_req_type req_type) 106 { 107 struct sk_buff *vendor_event; 108 struct wireless_dev *wdev; 109 struct vdev_osif_priv *osif_priv; 110 uint32_t len; 111 enum qca_wlan_audio_transport_switch_type switch_type; 112 uint8_t vdev_id = wlan_vdev_get_id(vdev); 113 114 osif_priv = wlan_vdev_get_ospriv(vdev); 115 if (!osif_priv) { 116 osif_err("Vdev %d osif_priv is null", vdev_id); 117 return; 118 } 119 120 wdev = osif_priv->wdev; 121 if (!wdev) { 122 osif_err("vdev %d wireless dev is null", vdev_id); 123 return; 124 } 125 126 switch_type = 127 osif_convert_audio_transport_switch_req_type_to_qca_type( 128 req_type); 129 len = nla_total_size(sizeof(uint8_t)) + NLMSG_HDRLEN; 130 131 vendor_event = wlan_cfg80211_vendor_event_alloc( 132 wdev->wiphy, wdev, len, 133 QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH_INDEX, 134 GFP_KERNEL); 135 136 if (!vendor_event) { 137 osif_err("vdev %d wlan_cfg80211_vendor_event_alloc failed", 138 vdev_id); 139 return; 140 } 141 142 if (nla_put_u8(vendor_event, 143 QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE, 144 switch_type)) { 145 osif_err("Vdev %d VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE put fail", 146 vdev_id); 147 wlan_cfg80211_vendor_free_skb(vendor_event); 148 return; 149 } 150 151 wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); 152 153 osif_nofl_debug("Vdev %d Audio Transport switch request %d sent", 154 vdev_id, switch_type); 155 } 156 157 QDF_STATUS osif_ll_lt_sap_request_for_audio_transport_switch( 158 struct wlan_objmgr_vdev *vdev, 159 enum qca_wlan_audio_transport_switch_type req_type) 160 { 161 return ucfg_ll_lt_sap_request_for_audio_transport_switch( 162 vdev, 163 osif_convert_audio_transport_switch_req_type_from_qca_type( 164 req_type)); 165 } 166 167 QDF_STATUS osif_ll_lt_sap_deliver_audio_transport_switch_resp( 168 struct wlan_objmgr_vdev *vdev, 169 enum qca_wlan_audio_transport_switch_type req_type, 170 enum qca_wlan_audio_transport_switch_status status) 171 { 172 static enum bearer_switch_status bs_status; 173 enum bearer_switch_req_type bs_req_type; 174 uint8_t vdev_id = wlan_vdev_get_id(vdev); 175 176 if (status == QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED) { 177 osif_nofl_debug("vdev %d Transport switch request %d completed", 178 vdev_id, req_type); 179 } else if (status == QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED) { 180 osif_nofl_debug("vdev %d Transport switch request %d rejected", 181 vdev_id, req_type); 182 } else { 183 osif_err("vdev %d Invalid transport switch status %d", vdev_id, 184 status); 185 return QDF_STATUS_E_INVAL; 186 } 187 bs_status = 188 osif_convert_audio_transport_switch_status_type_from_qca_type( 189 status); 190 bs_req_type = 191 osif_convert_audio_transport_switch_req_type_from_qca_type( 192 req_type); 193 194 ucfg_ll_lt_sap_deliver_audio_transport_switch_resp(vdev, bs_req_type, 195 bs_status); 196 197 return QDF_STATUS_SUCCESS; 198 } 199 200 static struct ll_sap_ops ll_sap_global_ops = { 201 .ll_sap_send_audio_transport_switch_req_cb = 202 wlan_osif_send_audio_transport_switch_req, 203 }; 204 205 QDF_STATUS osif_ll_sap_register_cb(void) 206 { 207 ucfg_ll_sap_register_cb(&ll_sap_global_ops); 208 return QDF_STATUS_SUCCESS; 209 } 210 211 void osif_ll_sap_unregister_cb(void) 212 { 213 ucfg_ll_sap_unregister_cb(); 214 } 215