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
osif_convert_audio_transport_switch_req_type_to_qca_type(enum bearer_switch_req_type req_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
osif_convert_audio_transport_switch_req_type_from_qca_type(enum qca_wlan_audio_transport_switch_type 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
osif_convert_audio_transport_switch_status_type_from_qca_type(enum qca_wlan_audio_transport_switch_status 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
wlan_osif_send_audio_transport_switch_req(struct wlan_objmgr_vdev * vdev,enum bearer_switch_req_type req_type)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 
osif_ll_lt_sap_request_for_audio_transport_switch(struct wlan_objmgr_vdev * vdev,enum qca_wlan_audio_transport_switch_type req_type)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 
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)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 
osif_ll_sap_register_cb(void)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 
osif_ll_sap_unregister_cb(void)211 void osif_ll_sap_unregister_cb(void)
212 {
213 	ucfg_ll_sap_unregister_cb();
214 }
215