1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Device Audio Class                                                    */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define UX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "ux_api.h"
28 #include "ux_device_class_audio.h"
29 #include "ux_device_class_audio10.h"
30 #include "ux_device_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_device_class_audio10_control_process            PORTABLE C      */
38 /*                                                           6.2.1        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function manages the based sent by the host on the control     */
46 /*    endpoints with a CLASS or VENDOR SPECIFIC type.                     */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    audio                                 Address of audio class        */
51 /*                                            instance                    */
52 /*    transfer                              Address of transfer request   */
53 /*                                            instance                    */
54 /*    group                                 Request process data          */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    Completion Status                                                   */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _ux_utility_short_get                 Get 2-byte value from buffer  */
63 /*    _ux_utility_short_put                 Put 2-byte value to buffer    */
64 /*    _ux_device_stack_transfer_request     Issue a transfer request      */
65 /*    _ux_device_stack_endpoint_stall       Endpoint stall                */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    Application                                                         */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
76 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            resulting in version 6.1    */
78 /*  04-02-2021     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            added volume RES support,   */
80 /*                                            resulting in version 6.1.6  */
81 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            internal clean up,          */
83 /*                                            resulting in version 6.1.11 */
84 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            added sampling control,     */
86 /*                                            resulting in version 6.1.12 */
87 /*  03-08-2023     Chaoqiong Xiao           Modified comment(s),          */
88 /*                                            fixed a macro name,         */
89 /*                                            resulting in version 6.2.1  */
90 /*                                                                        */
91 /**************************************************************************/
_ux_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO * audio,UX_SLAVE_TRANSFER * transfer,UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP * group)92 UINT _ux_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO *audio,
93     UX_SLAVE_TRANSFER *transfer, UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP *group)
94 {
95 
96 UX_SLAVE_ENDPOINT                   *endpoint;
97 UX_DEVICE_CLASS_AUDIO10_CONTROL     *control;
98 UCHAR                               request;
99 UCHAR                               request_type;
100 UCHAR                               unit_id, ep_addr;
101 UCHAR                               control_selector;
102 UCHAR                               channel_number;
103 ULONG                               request_length;
104 UCHAR                               *desc;
105 ULONG                               sam, min, max, pos;
106 ULONG                               i;
107 
108 
109     /* Get instances.  */
110     endpoint = &audio -> ux_device_class_audio_device -> ux_slave_device_control_endpoint;
111     transfer = &endpoint -> ux_slave_endpoint_transfer_request;
112 
113     /* Extract all necessary fields of the request.  */
114     request          = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_REQUEST);
115     request_type     = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_REQUEST_TYPE);
116     unit_id          = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_ENEITY_ID);
117     ep_addr          = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_ENDPOINT);
118     control_selector = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_CONTROL_SELECTOR);
119     channel_number   = *(transfer -> ux_slave_transfer_request_setup + UX_DEVICE_CLASS_AUDIO_REQUEST_CHANNEL_NUMBER);
120     request_length   = _ux_utility_short_get(transfer -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
121 
122     /* Process controls one by one.  */
123     for (i = 0; i < group -> ux_device_class_audio10_control_group_controls_nb; i ++)
124     {
125         control = &group -> ux_device_class_audio10_control_group_controls[i];
126 
127         /* Reset change map.  */
128         control -> ux_device_class_audio10_control_changed = 0;
129 
130         /* We handle endpoint requests.  */
131         if ((request_type & UX_REQUEST_TARGET) == UX_REQUEST_TARGET_ENDPOINT &&
132             ep_addr == control -> ux_device_class_audio10_control_ep_addr)
133         {
134 
135             /* Handle the request.  */
136             switch(request)
137             {
138             case UX_DEVICE_CLASS_AUDIO10_SET_CUR:
139 
140                 /* Only sampling frequency control is supported.  */
141                 if (control_selector != UX_DEVICE_CLASS_AUDIO10_EP_SAMPLING_FREQ_CONTROL)
142                     break;
143 
144                 /* Length check.  */
145                 if (request_length != 3)
146                     break;
147 
148                 /* If frequencies not specified, no modification accepted.  */
149                 if (control -> ux_device_class_audio10_control_sam_freq_types == UX_NULL)
150                     return(UX_SUCCESS);
151 
152                 /* Check sampling frequency types (UAC 1.0 Format Type I : bSamFreqType ..) for MIN and MAX.  */
153                 desc = control -> ux_device_class_audio10_control_sam_freq_types;
154                 if (desc[0] == 0)
155                 {
156                     min = ((ULONG)desc[1]) | ((ULONG)desc[2] << 8) | ((ULONG)desc[3] << 16);
157                     max = ((ULONG)desc[4]) | ((ULONG)desc[5] << 8) | ((ULONG)desc[6] << 16);
158                 }
159                 else
160                 {
161                     min = 0xFFFFFFFF;
162                     max = 0x00000000;
163                     for (pos = 1;
164                          pos < (ULONG)desc[0] * 3 + 1; /* Calculate from byte, no overflow.  */
165                          pos += 3)
166                     {
167                         sam = (ULONG)desc[pos + 0] | ((ULONG)desc[pos + 1] << 8) | ((ULONG)desc[pos + 2] << 16);
168                         if (sam > max)
169                             max = sam;
170                         if (sam < min)
171                             min = sam;
172                     }
173                 }
174 
175                 /* Accept frequency any way.
176                  * If it's not in range, round to min or max.
177                  * If it's in range it's not rounded, application should check and round it.  */
178                 sam = ((ULONG)transfer -> ux_slave_transfer_request_data_pointer[0]      ) |
179                       ((ULONG)transfer -> ux_slave_transfer_request_data_pointer[1] <<  8) |
180                       ((ULONG)transfer -> ux_slave_transfer_request_data_pointer[2] << 16);
181                 if (sam < min)
182                     sam = min;
183                 if (sam > max)
184                     sam = max;
185                 control -> ux_device_class_audio10_control_sam_freq = sam;
186                 control -> ux_device_class_audio10_control_changed = UX_DEVICE_CLASS_AUDIO10_CONTROL_FREQUENCY_CHANGED;
187                 return(UX_SUCCESS);
188 
189             case UX_DEVICE_CLASS_AUDIO10_GET_CUR:
190 
191                 /* Sampling frequency control is supported.  */
192                 if (control_selector != UX_DEVICE_CLASS_AUDIO10_EP_SAMPLING_FREQ_CONTROL)
193                     break;
194 
195                 /* Check host buffer.  */
196                 if (request_length < 3)
197                     break;
198 
199                 /* Put sample frequency.  */
200                 sam = control -> ux_device_class_audio10_control_sam_freq;
201                 transfer -> ux_slave_transfer_request_data_pointer[0] = UX_DW0(sam);
202                 transfer -> ux_slave_transfer_request_data_pointer[1] = UX_DW1(sam);
203                 transfer -> ux_slave_transfer_request_data_pointer[2] = UX_DW2(sam);
204                 _ux_device_stack_transfer_request(transfer, 3, request_length);
205                 return(UX_SUCCESS);
206 
207             default:
208                 break;
209             }
210         }
211 
212         /* We handle feature unit requests.  */
213         if ((request_type & UX_REQUEST_TARGET) == UX_REQUEST_TARGET_INTERFACE &&
214             unit_id == control -> ux_device_class_audio10_control_fu_id)
215         {
216 
217             /* Handle the request.  */
218             switch(request)
219             {
220             case UX_DEVICE_CLASS_AUDIO10_SET_CUR:
221 
222                 /* We only support master channel, so channel number must be 0 or 0xFF.  */
223                 if (channel_number != 0 && channel_number != 0xFF)
224                     break;
225 
226                 /* Set request.  */
227                 switch(control_selector)
228                 {
229                 case UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL:
230 
231                     if (transfer -> ux_slave_transfer_request_actual_length < 1)
232 
233                         /* No change applied.  */
234                         break;
235 
236                     if (control -> ux_device_class_audio10_control_mute[0] != transfer -> ux_slave_transfer_request_data_pointer[0])
237                     {
238                         control -> ux_device_class_audio10_control_changed = UX_DEVICE_CLASS_AUDIO10_CONTROL_MUTE_CHANGED;
239                         control -> ux_device_class_audio10_control_mute[0] = transfer -> ux_slave_transfer_request_data_pointer[0];
240 
241                     }
242 
243                     /* Done success.  */
244                     return(UX_SUCCESS);
245 
246                 case UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL:
247 
248                     if (transfer -> ux_slave_transfer_request_actual_length < 2)
249 
250                         /* No change applied.  */
251                         break;
252 
253                     if (control -> ux_device_class_audio10_control_volume[0] != (SHORT)_ux_utility_short_get(transfer -> ux_slave_transfer_request_data_pointer))
254                     {
255                         control -> ux_device_class_audio10_control_changed = UX_DEVICE_CLASS_AUDIO10_CONTROL_VOLUME_CHANGED;
256                         control -> ux_device_class_audio10_control_volume[0] = (SHORT)_ux_utility_short_get(transfer -> ux_slave_transfer_request_data_pointer);
257                     }
258 
259                     /* Done success.  */
260                     return(UX_SUCCESS);
261 
262 
263                 default:
264 
265                     /* No change applied.  */
266                     break;
267                 }
268 
269                 /* Request or parameter problem.  */
270                 break;
271 
272             case UX_DEVICE_CLASS_AUDIO10_GET_MIN:
273             case UX_DEVICE_CLASS_AUDIO10_GET_MAX:
274             case UX_DEVICE_CLASS_AUDIO10_GET_RES:
275             case UX_DEVICE_CLASS_AUDIO10_GET_CUR:
276 
277                 /* We only support master channel, so channel number must be 0 or 0xFF.  */
278                 if (channel_number != 0 && channel_number != 0xFF)
279                     break;
280 
281                 /* Get request.  */
282                 switch(control_selector)
283                 {
284                 case UX_DEVICE_CLASS_AUDIO10_FU_MUTE_CONTROL:
285 
286                     /* We only support _CUR.  */
287                     if (request != UX_DEVICE_CLASS_AUDIO10_GET_CUR)
288                         break;
289 
290                     /* Not enough buffer for data.  */
291                     if (request_length < 1)
292                         break;
293 
294                     /* Send mute status.  */
295                     transfer -> ux_slave_transfer_request_data_pointer[0] = (UCHAR)control -> ux_device_class_audio10_control_mute[0];
296                     _ux_device_stack_transfer_request(transfer, 1, request_length);
297 
298                     /* Done success.  */
299                     return(UX_SUCCESS);
300 
301                 case UX_DEVICE_CLASS_AUDIO10_FU_VOLUME_CONTROL:
302 
303                     /* Not enough buffer for data.  */
304                     if (request_length < 2)
305                         break;
306 
307                     /* Send volume value.  */
308                     _ux_utility_short_put(transfer -> ux_slave_transfer_request_data_pointer, (USHORT)
309                                           (request == UX_DEVICE_CLASS_AUDIO10_GET_MIN ? control -> ux_device_class_audio10_control_volume_min[0] :
310                                            (request == UX_DEVICE_CLASS_AUDIO10_GET_MAX ? control -> ux_device_class_audio10_control_volume_max[0] :
311                                             (request == UX_DEVICE_CLASS_AUDIO10_GET_RES ? UX_MAX(1, control -> ux_device_class_audio10_control_volume_res[0]) :
312                                               control -> ux_device_class_audio10_control_volume[0]))));
313                     _ux_device_stack_transfer_request(transfer, 2, request_length);
314 
315                     /* Done success.  */
316                     return(UX_SUCCESS);
317 
318                 default:
319                     break;
320                 }
321                 break;
322 
323             default:
324                 break;
325             }
326 
327             /* We are here when there is error, break the loop.  */
328             break;
329         }
330 
331         /* Now try next.  */
332     }
333 
334 
335     /* Request or parameter not supported.  */
336     _ux_device_stack_endpoint_stall(endpoint);
337 
338     /* Done error.  */
339     return(UX_ERROR);
340 }
341 
342 
343 /**************************************************************************/
344 /*                                                                        */
345 /*  FUNCTION                                               RELEASE        */
346 /*                                                                        */
347 /*    _uxe_device_class_audio10_control_process           PORTABLE C      */
348 /*                                                           6.2.1        */
349 /*  AUTHOR                                                                */
350 /*                                                                        */
351 /*    Chaoqiong Xiao, Microsoft Corporation                               */
352 /*                                                                        */
353 /*  DESCRIPTION                                                           */
354 /*                                                                        */
355 /*    This function checks errors in control processing function call.    */
356 /*                                                                        */
357 /*  INPUT                                                                 */
358 /*                                                                        */
359 /*    audio                                 Address of audio class        */
360 /*                                            instance                    */
361 /*    transfer                              Address of transfer request   */
362 /*                                            instance                    */
363 /*    group                                 Request process data          */
364 /*                                                                        */
365 /*  OUTPUT                                                                */
366 /*                                                                        */
367 /*    Completion Status                                                   */
368 /*                                                                        */
369 /*  CALLS                                                                 */
370 /*                                                                        */
371 /*    _ux_device_class_audio10_control_process                            */
372 /*                                          Process control requests      */
373 /*                                                                        */
374 /*  CALLED BY                                                             */
375 /*                                                                        */
376 /*    Application                                                         */
377 /*                                                                        */
378 /*  RELEASE HISTORY                                                       */
379 /*                                                                        */
380 /*    DATE              NAME                      DESCRIPTION             */
381 /*                                                                        */
382 /*  03-08-2023     Chaoqiong Xiao           Initial Version 6.2.1         */
383 /*                                                                        */
384 /**************************************************************************/
_uxe_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO * audio,UX_SLAVE_TRANSFER * transfer,UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP * group)385 UINT _uxe_device_class_audio10_control_process(UX_DEVICE_CLASS_AUDIO *audio,
386     UX_SLAVE_TRANSFER *transfer, UX_DEVICE_CLASS_AUDIO10_CONTROL_GROUP *group)
387 {
388 
389     /* Sanity checks.  */
390     if (audio == UX_NULL || transfer == UX_NULL || group == UX_NULL)
391         return(UX_INVALID_PARAMETER);
392 
393     /* Process control request.  */
394     return(_ux_device_class_audio10_control_process(audio, transfer, group));
395 }
396