1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** USBX Component */
16 /** */
17 /** Audio Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_audio.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_audio_entity_control_get PORTABLE C */
37 /* 6.1.12 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function obtains the static values for a single audio control */
45 /* control on either the master channel or a specific channel. */
46 /* */
47 /* Note only control value of BYTE, WORD and DWORD (<4) is supported. */
48 /* E.g., Graphic Equalizer Control is not supported. */
49 /* */
50 /* INPUT */
51 /* */
52 /* audio Pointer to audio class */
53 /* audio_control Pointer to audio control */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* Completion Status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_host_stack_class_instance_verify Verify instance is valid */
62 /* _ux_host_stack_transfer_request Process transfer request */
63 /* _ux_host_semaphore_get Get semaphore */
64 /* _ux_host_semaphore_put Release semaphore */
65 /* _ux_host_mutex_on Get mutex */
66 /* _ux_host_mutex_off Release mutex */
67 /* _ux_utility_memory_allocate Allocate memory block */
68 /* _ux_utility_memory_free Release memory block */
69 /* _ux_utility_short_get Read 16-bit value */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* Application */
74 /* Audio Class */
75 /* */
76 /* RELEASE HISTORY */
77 /* */
78 /* DATE NAME DESCRIPTION */
79 /* */
80 /* 07-29-2022 Chaoqiong Xiao Initial Version 6.1.12 */
81 /* */
82 /**************************************************************************/
_ux_host_class_audio_entity_control_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_CONTROL * audio_control)83 UINT _ux_host_class_audio_entity_control_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_CONTROL *audio_control)
84 {
85
86 UINT status;
87 UCHAR * control_buffer;
88 ULONG actual_size;
89 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
90 ULONG n_subs, sub, pos, min, max, res, size;
91 #endif
92
93
94 /* Validate control size. */
95 if (audio_control -> ux_host_class_audio_control_size > 4)
96 return(UX_INVALID_PARAMETER);
97
98 /* Ensure the instance is valid. */
99 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
100 {
101
102 /* Error trap. */
103 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
104
105 /* If trace is enabled, insert this event into the trace buffer. */
106 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
107
108 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
109 }
110
111 /* Protect thread reentry to this instance. */
112 _ux_host_mutex_on(&audio -> ux_host_class_audio_mutex);
113
114 #if defined(UX_HOST_CLASS_AUDIO_2_SUPPORT)
115 if (_ux_host_class_audio_protocol_get(audio) == UX_HOST_CLASS_AUDIO_PROTOCOL_IP_VERSION_02_00)
116 {
117
118 /* Need to allocate enough memory for the control buffer. */
119 /* Max RANGE size (single item): 2+4*3=14. */
120 control_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 16);
121 if (control_buffer == UX_NULL)
122 {
123
124 /* Return an error. */
125 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
126 return(UX_MEMORY_INSUFFICIENT);
127 }
128
129 /* Issue GET RANGE request. */
130 status = _ux_host_class_audio_control_request(audio, 0,
131 UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE,
132 UX_CLASS_AUDIO20_RANGE,
133 audio_control -> ux_host_class_audio_control_channel |
134 (audio_control -> ux_host_class_audio_control << 8),
135 audio_control -> ux_host_class_audio_control_entity,
136 control_buffer, 16, &actual_size);
137
138 /* Check request status code. */
139 if (status == UX_SUCCESS)
140 {
141
142 /* Check returned size. */
143 if (actual_size < 2)
144 {
145
146 /* Return an error. */
147 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
148 _ux_utility_memory_free(control_buffer);
149 return(UX_TRANSFER_ERROR);
150 }
151
152 /* Check wNumSubRanges. */
153 n_subs = _ux_utility_short_get(control_buffer);
154 if (n_subs > 1)
155 {
156
157 /* wNumSubRanges is short, control size max 4, no overflow. */
158 size = 2 + n_subs * audio_control -> ux_host_class_audio_control_size;
159 if (size > 16)
160 {
161
162 /* Issue GET RANGE again with larger buffer. */
163 _ux_utility_memory_free(control_buffer);
164 control_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, size);
165 if (control_buffer == UX_NULL)
166 {
167
168 /* Return an error. */
169 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
170 return(UX_MEMORY_INSUFFICIENT);
171 }
172
173 /* Issue GET RANGE request. */
174 status = _ux_host_class_audio_control_request(audio, 0,
175 UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE,
176 UX_CLASS_AUDIO20_RANGE,
177 audio_control -> ux_host_class_audio_control_channel |
178 (audio_control -> ux_host_class_audio_control << 8),
179 audio_control -> ux_host_class_audio_control_entity,
180 control_buffer, size, &actual_size);
181
182 if ((status != UX_SUCCESS) || (actual_size != size))
183 {
184
185 /* Return an error. */
186 _ux_utility_memory_free(control_buffer);
187 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
188 return(UX_TRANSFER_ERROR);
189 }
190 }
191 }
192
193 /* Parse returned values. */
194 audio_control -> ux_host_class_audio_control_max = 0;
195 audio_control -> ux_host_class_audio_control_min = 0xFFFFFFFF;
196 audio_control -> ux_host_class_audio_control_res = 0;
197 pos = 2;
198 for (sub = 0; sub < n_subs; sub ++)
199 {
200
201 /* Get MIN, MAX and POS. */
202 switch(audio_control -> ux_host_class_audio_control_size)
203 {
204 case 1:
205 min = *(control_buffer + pos);
206 pos ++;
207 max = *(control_buffer + pos);
208 pos ++;
209 res = *(control_buffer + pos);
210 pos ++;
211 break;
212
213 case 2:
214 min = _ux_utility_short_get(control_buffer + pos);
215 pos += 2;
216 max = _ux_utility_short_get(control_buffer + pos);
217 pos += 2;
218 res = _ux_utility_short_get(control_buffer + pos);
219 pos += 2;
220 break;
221
222 default:
223 min = _ux_utility_long_get(control_buffer + pos);
224 pos += 4;
225 max = _ux_utility_long_get(control_buffer + pos);
226 pos += 4;
227 res = _ux_utility_long_get(control_buffer + pos);
228 pos += 4;
229 break;
230 }
231
232 /* Keep MAX. */
233 if (audio_control -> ux_host_class_audio_control_max < max)
234 audio_control -> ux_host_class_audio_control_max = max;
235
236 /* Keep MIN. */
237 if (audio_control -> ux_host_class_audio_control_min > min)
238 audio_control -> ux_host_class_audio_control_min = min;
239
240 /* If there is RES, keep the min of RES. */
241 if (audio_control -> ux_host_class_audio_control_res == 0)
242 audio_control -> ux_host_class_audio_control_res = res;
243 else if (res < audio_control -> ux_host_class_audio_control_res)
244 audio_control -> ux_host_class_audio_control_res = res;
245 }
246
247 /* If there is list of RANGEs and no RES, guess it (average of max-min). */
248 if (n_subs > 1 && audio_control -> ux_host_class_audio_control_res == 0)
249 {
250 audio_control -> ux_host_class_audio_control_res =
251 (audio_control -> ux_host_class_audio_control_max -
252 audio_control -> ux_host_class_audio_control_min) / n_subs;
253 }
254 }
255 }
256 else
257 #endif
258 {
259
260 /* Need to allocate memory for the control buffer, max DWORD (4). */
261 control_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 4);
262 if (control_buffer == UX_NULL)
263 {
264
265 /* Return an error. */
266 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
267 return(UX_MEMORY_INSUFFICIENT);
268 }
269
270 /* Issue GET_MIN request. */
271 * (ULONG *)control_buffer = 0;
272 status = _ux_host_class_audio_control_request(audio, 0,
273 UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE,
274 UX_HOST_CLASS_AUDIO_GET_MIN,
275 audio_control -> ux_host_class_audio_control_channel |
276 (audio_control -> ux_host_class_audio_control << 8),
277 audio_control -> ux_host_class_audio_control_entity,
278 control_buffer, 4, &actual_size);
279
280 /* Check for correct transfer and entire control buffer returned.
281 * Start GET_MAX request. */
282 if (status == UX_SUCCESS)
283 {
284
285 /* Update the MIN static value for the caller. */
286 audio_control -> ux_host_class_audio_control_min = _ux_utility_long_get(control_buffer);
287
288 /* Issue GET_MAX request. */
289 * (ULONG *)control_buffer = 0;
290 status = _ux_host_class_audio_control_request(audio, 0,
291 UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE,
292 UX_HOST_CLASS_AUDIO_GET_MAX,
293 audio_control -> ux_host_class_audio_control_channel |
294 (audio_control -> ux_host_class_audio_control << 8),
295 audio_control -> ux_host_class_audio_control_entity,
296 control_buffer, 4, &actual_size);
297 }
298
299 /* Check for correct transfer and entire control buffer returned.
300 * Start GET_RES request. */
301 if (status == UX_SUCCESS)
302 {
303
304 /* Update the MAX static value for the caller. */
305 audio_control -> ux_host_class_audio_control_max = _ux_utility_long_get(control_buffer);
306
307 /* Issue GET_RES request. */
308 * (ULONG *)control_buffer = 0;
309 status = _ux_host_class_audio_control_request(audio, 0,
310 UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE,
311 UX_HOST_CLASS_AUDIO_GET_RES,
312 audio_control -> ux_host_class_audio_control_channel |
313 (audio_control -> ux_host_class_audio_control << 8),
314 audio_control -> ux_host_class_audio_control_entity,
315 control_buffer, 4, &actual_size);
316 }
317
318 /* Check for correct transfer and entire control buffer returned. */
319 if (status == UX_SUCCESS)
320 {
321
322 /* Update the RES static value for the caller. */
323 audio_control -> ux_host_class_audio_control_res = _ux_utility_long_get(control_buffer);
324 }
325 }
326
327 /* Free all used resources. */
328 _ux_utility_memory_free(control_buffer);
329
330 /* Unprotect thread reentry to this instance. */
331 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
332
333 /* Return completion status. */
334 return(status);
335 }
336
337
338 /**************************************************************************/
339 /* */
340 /* FUNCTION RELEASE */
341 /* */
342 /* _uxe_host_class_audio_entity_control_get PORTABLE C */
343 /* 6.3.0 */
344 /* AUTHOR */
345 /* */
346 /* Chaoqiong Xiao, Microsoft Corporation */
347 /* */
348 /* DESCRIPTION */
349 /* */
350 /* This function checks errors in audio entity control get function */
351 /* call. */
352 /* */
353 /* INPUT */
354 /* */
355 /* audio Pointer to audio class */
356 /* audio_control Pointer to audio control */
357 /* */
358 /* OUTPUT */
359 /* */
360 /* Status */
361 /* */
362 /* CALLS */
363 /* */
364 /* _uxe_host_class_audio_entity_control_get */
365 /* Get audio entity control */
366 /* */
367 /* CALLED BY */
368 /* */
369 /* Application */
370 /* */
371 /* RELEASE HISTORY */
372 /* */
373 /* DATE NAME DESCRIPTION */
374 /* */
375 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
376 /* */
377 /**************************************************************************/
_uxe_host_class_audio_entity_control_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_CONTROL * audio_control)378 UINT _uxe_host_class_audio_entity_control_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_CONTROL *audio_control)
379 {
380
381 /* Sanity checks. */
382 if ((audio == UX_NULL) || (audio_control == UX_NULL))
383 return(UX_INVALID_PARAMETER);
384
385 /* Invoke entity control get function. */
386 return(_ux_host_class_audio_entity_control_get(audio, audio_control));
387 }
388