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