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