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 /** USBX Component                                                        */
15 /**                                                                       */
16 /**   Device Audio Class                                                  */
17 /**                                                                       */
18 /**************************************************************************/
19 /**************************************************************************/
20 
21 #define UX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "ux_api.h"
27 #include "ux_device_class_audio.h"
28 #include "ux_device_stack.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _ux_device_class_audio_initialize                   PORTABLE C      */
36 /*                                                           6.2.0        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function initializes the USB Audio device.                     */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    command                               Pointer to audio command      */
48 /*                                                                        */
49 /*  OUTPUT                                                                */
50 /*                                                                        */
51 /*    Completion Status                                                   */
52 /*                                                                        */
53 /*  CALLS                                                                 */
54 /*                                                                        */
55 /*    _ux_utility_memory_allocate           Allocate memory               */
56 /*    _ux_utility_memory_copy               Copy memory                   */
57 /*    _ux_utility_memory_free               Free memory                   */
58 /*    _ux_device_thread_create              Create thread to use          */
59 /*    _ux_device_thread_delete              Delete thread                 */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    Device Audio Class                                                  */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
70 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
71 /*                                            verified memset and memcpy  */
72 /*                                            cases, used UX prefix to    */
73 /*                                            refer to TX symbols instead */
74 /*                                            of using them directly,     */
75 /*                                            resulting in version 6.1    */
76 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            refined macros names,       */
78 /*                                            added feedback support,     */
79 /*                                            resulting in version 6.1.10 */
80 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            fixed standalone compile,   */
82 /*                                            resulting in version 6.1.11 */
83 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
84 /*                                            added interrupt support,    */
85 /*                                            refined internal logic,     */
86 /*                                            resulting in version 6.1.12 */
87 /*  10-31-2022     Yajun Xia                Modified comment(s),          */
88 /*                                            added standalone support,   */
89 /*                                            resulting in version 6.2.0  */
90 /*                                                                        */
91 /**************************************************************************/
_ux_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND * command)92 UINT  _ux_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND *command)
93 {
94 
95 UINT                                    status = UX_SUCCESS;
96 UX_DEVICE_CLASS_AUDIO                   *audio;
97 UX_DEVICE_CLASS_AUDIO_PARAMETER         *audio_parameter;
98 UX_DEVICE_CLASS_AUDIO_STREAM            *stream;
99 UX_DEVICE_CLASS_AUDIO_STREAM_PARAMETER  *stream_parameter;
100 UX_SLAVE_CLASS                          *audio_class;
101 ULONG                                   memory_size;
102 ULONG                                   streams_size;
103 ULONG                                   i;
104 
105 
106     /* Get the class container.  */
107     audio_class =  command -> ux_slave_class_command_class_ptr;
108 
109     /* Get the pointer to the application parameters for the audio class.  */
110     audio_parameter = (UX_DEVICE_CLASS_AUDIO_PARAMETER *)command -> ux_slave_class_command_parameter;
111 
112     /* Create an instance of the device audio class, with additional streams and controls instances.  */
113     memory_size  = sizeof(UX_DEVICE_CLASS_AUDIO);
114 
115     /* Put 0 to default result.  */
116     streams_size = 0;
117 
118     /* Confirm there is no overflow on multiply.  */
119     UX_UTILITY_MULC_SAFE(audio_parameter -> ux_device_class_audio_parameter_streams_nb, (ULONG)sizeof(UX_DEVICE_CLASS_AUDIO_STREAM), streams_size, status);
120     if (status != UX_SUCCESS)
121         return(status);
122 
123     /* Confirm there is no overflow on add.  */
124     UX_UTILITY_ADD_SAFE(memory_size, streams_size, memory_size, status);
125     if (status != UX_SUCCESS)
126         return(status);
127 
128     /* Create buffer for audio and controls.  */
129     audio = (UX_DEVICE_CLASS_AUDIO *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
130 
131     /* Check for successful allocation.  */
132     if (audio == UX_NULL)
133         return(UX_MEMORY_INSUFFICIENT);
134 
135 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
136 
137     /* Create resources for interrupt endpoint support.  */
138 
139     /* Get status data size.  */
140     audio -> ux_device_class_audio_status_size =
141                 audio_parameter -> ux_device_class_audio_parameter_status_size;
142 
143     /* Calculate queue size in bytes.  */
144     if (UX_OVERFLOW_CHECK_MULV_ULONG(
145         audio_parameter -> ux_device_class_audio_parameter_status_queue_size,
146         audio_parameter -> ux_device_class_audio_parameter_status_size))
147     {
148         _ux_utility_memory_free(audio);
149         return(UX_MATH_OVERFLOW);
150     }
151     memory_size = audio_parameter -> ux_device_class_audio_parameter_status_queue_size *
152                 audio_parameter -> ux_device_class_audio_parameter_status_size;
153     audio -> ux_device_class_audio_status_queue_bytes = memory_size;
154 
155 #if !defined(UX_DEVICE_STANDALONE)
156     if (UX_OVERFLOW_CHECK_ADD_ULONG(memory_size, UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE))
157     {
158         _ux_utility_memory_free(audio);
159         return(UX_MATH_OVERFLOW);
160     }
161     memory_size += UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE;
162 
163     audio_class -> ux_slave_class_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
164     if (audio_class -> ux_slave_class_thread_stack == UX_NULL)
165         status = UX_MEMORY_INSUFFICIENT;
166 
167     if (status == UX_SUCCESS)
168     {
169         status = _ux_device_thread_create(&audio_class -> ux_slave_class_thread,
170                         "ux_device_class_audio_status_thread",
171                         _ux_device_class_audio_interrupt_thread_entry, (ULONG)(ALIGN_TYPE)audio,
172                         audio_class -> ux_slave_class_thread_stack,
173                         UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE,
174                         UX_THREAD_PRIORITY_CLASS, UX_THREAD_PRIORITY_CLASS,
175                         UX_NO_TIME_SLICE, UX_DONT_START);
176         if (status == UX_SUCCESS)
177         {
178             UX_THREAD_EXTENSION_PTR_SET(&(audio_class -> ux_slave_class_thread), audio)
179 
180             status = _ux_device_semaphore_create(&audio -> ux_device_class_audio_status_semaphore,
181                                 "ux_device_class_audio_status_semaphore", 0);
182             if (status == UX_SUCCESS)
183             {
184                 status = _ux_device_mutex_create(&audio -> ux_device_class_audio_status_mutex,
185                                 "ux_device_class_audio_status_mutex");
186                 if (status != UX_SUCCESS)
187                     status = UX_MUTEX_ERROR;
188 
189                 if (status != UX_SUCCESS)
190                     _ux_device_semaphore_delete(&audio -> ux_device_class_audio_status_semaphore);
191             }
192             else
193                 status = UX_SEMAPHORE_ERROR;
194 
195             if (status != UX_SUCCESS)
196                 _ux_device_thread_delete(&audio_class -> ux_slave_class_thread);
197         }
198         else
199             status = UX_THREAD_ERROR;
200 
201         if (status != UX_SUCCESS)
202         {
203             _ux_utility_memory_free(audio_class -> ux_slave_class_thread_stack);
204             audio_class -> ux_slave_class_thread_stack = UX_NULL;
205         }
206     }
207 
208     if (status != UX_SUCCESS)
209     {
210         _ux_utility_memory_free(audio);
211         return(status);
212     }
213 
214     /* Status queue locates right after status stack.  */
215     audio -> ux_device_class_audio_status_queue =
216                         (UCHAR *)audio_class -> ux_slave_class_thread_stack +
217                         UX_DEVICE_CLASS_AUDIO_INTERRUPT_THREAD_STACK_SIZE;
218 #else
219     audio -> ux_device_class_audio_status_queue = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
220 
221     /* Check for successful allocation.  */
222     if (audio -> ux_device_class_audio_status_queue == UX_NULL)
223     {
224         _ux_utility_memory_free(audio);
225         return(UX_MEMORY_INSUFFICIENT);
226     }
227 #endif
228 
229 #endif
230 
231     /* Save streams.  */
232     if (streams_size)
233     {
234         audio -> ux_device_class_audio_streams = (UX_DEVICE_CLASS_AUDIO_STREAM *)((UCHAR *)audio + sizeof(UX_DEVICE_CLASS_AUDIO));
235         audio -> ux_device_class_audio_streams_nb = audio_parameter -> ux_device_class_audio_parameter_streams_nb;
236     }
237 
238     /* Allocate resources for streams.  */
239     stream = audio -> ux_device_class_audio_streams;
240     stream_parameter = audio_parameter -> ux_device_class_audio_parameter_streams;
241     for (i = 0; i < audio -> ux_device_class_audio_streams_nb; i ++)
242     {
243 
244         /* Create memory block based on max frame buffer size and max number of frames buffered.
245            Each frame require some additional header memory (8 bytes).  */
246         stream -> ux_device_class_audio_stream_frame_buffer_size = stream_parameter -> ux_device_class_audio_stream_parameter_max_frame_buffer_size;
247 
248         if (UX_OVERFLOW_CHECK_ADD_USHORT(stream -> ux_device_class_audio_stream_frame_buffer_size, 8))
249         {
250             status = UX_ERROR;
251             break;
252         }
253         stream -> ux_device_class_audio_stream_frame_buffer_size += 8;
254 
255         if (UX_OVERFLOW_CHECK_MULV_ULONG(stream -> ux_device_class_audio_stream_frame_buffer_size,
256             stream_parameter -> ux_device_class_audio_stream_parameter_max_frame_buffer_nb))
257         {
258             status = UX_ERROR;
259             break;
260         }
261         memory_size = stream -> ux_device_class_audio_stream_frame_buffer_size *
262                             stream_parameter -> ux_device_class_audio_stream_parameter_max_frame_buffer_nb;
263 
264         /* Create block of buffer buffer is cache safe for USB transfer.  */
265         stream -> ux_device_class_audio_stream_buffer = (UCHAR *)_ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
266 
267         /* Check for successful allocation.  */
268         if (stream -> ux_device_class_audio_stream_buffer == UX_NULL)
269         {
270             status = UX_MEMORY_INSUFFICIENT;
271             break;
272         }
273 
274         stream -> ux_device_class_audio_stream_buffer_size = memory_size;
275         stream -> ux_device_class_audio_stream_transfer_pos = (UX_DEVICE_CLASS_AUDIO_FRAME *)stream -> ux_device_class_audio_stream_buffer;
276         stream -> ux_device_class_audio_stream_access_pos = stream -> ux_device_class_audio_stream_transfer_pos;
277 
278 #if !defined(UX_DEVICE_STANDALONE)
279 
280         /* Create memory block for streaming thread stack in addition.  */
281         if (stream_parameter -> ux_device_class_audio_stream_parameter_thread_stack_size == 0)
282             memory_size = UX_DEVICE_CLASS_AUDIO_FEEDBACK_THREAD_STACK_SIZE;
283         else
284             memory_size = stream_parameter -> ux_device_class_audio_stream_parameter_thread_stack_size;
285         stream -> ux_device_class_audio_stream_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
286 
287         /* Check for successful allocation.  */
288         if (stream -> ux_device_class_audio_stream_thread_stack == UX_NULL)
289         {
290             status = UX_MEMORY_INSUFFICIENT;
291             break;
292         }
293 
294         /* Create streaming thread.  */
295         status =  _ux_device_thread_create(&stream -> ux_device_class_audio_stream_thread , "ux_device_class_audio_stream_thread",
296                     stream_parameter -> ux_device_class_audio_stream_parameter_thread_entry,
297                     (ULONG)(ALIGN_TYPE)stream, (VOID *) stream -> ux_device_class_audio_stream_thread_stack,
298                     memory_size, UX_THREAD_PRIORITY_CLASS,
299                     UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
300 
301         /* Check for successful allocation.  */
302         if (status != UX_SUCCESS)
303         {
304             _ux_utility_memory_free(stream -> ux_device_class_audio_stream_thread_stack);
305             stream -> ux_device_class_audio_stream_thread_stack = UX_NULL;
306             break;
307         }
308 
309         UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_audio_stream_thread), stream)
310 #else
311 
312         /* Save task function for streaming.  */
313         stream -> ux_device_class_audio_stream_task_function = stream_parameter -> ux_device_class_audio_stream_parameter_task_function;
314 #endif
315 
316 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
317 
318 #if !defined(UX_DEVICE_STANDALONE)
319 
320         /* Check entry to confirm feedback is supported.  */
321         if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_entry)
322         {
323             /* Create memory block for streaming thread stack in addition.  */
324             if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_stack_size == 0)
325                 memory_size = UX_THREAD_STACK_SIZE;
326             else
327                 memory_size = stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_stack_size;
328             stream -> ux_device_class_audio_stream_feedback_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
329 
330             /* Check for successful allocation.  */
331             if (stream -> ux_device_class_audio_stream_feedback_thread_stack == UX_NULL)
332             {
333                 status = UX_MEMORY_INSUFFICIENT;
334                 break;
335             }
336 
337             /* Create streaming thread.  */
338             status =  _ux_utility_thread_create(&stream -> ux_device_class_audio_stream_feedback_thread , "ux_device_class_audio_stream_feedback_thread",
339                         stream_parameter -> ux_device_class_audio_stream_parameter_feedback_thread_entry,
340                         (ULONG)(ALIGN_TYPE)stream, (VOID *) stream -> ux_device_class_audio_stream_feedback_thread_stack,
341                         memory_size, UX_THREAD_PRIORITY_CLASS,
342                         UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
343 
344             /* Check for successful allocation.  */
345             if (status != UX_SUCCESS)
346             {
347                 _ux_utility_memory_free(stream -> ux_device_class_audio_stream_feedback_thread_stack);
348                 stream -> ux_device_class_audio_stream_feedback_thread_stack = UX_NULL;
349                 break;
350             }
351 
352             UX_THREAD_EXTENSION_PTR_SET(&(stream -> ux_device_class_audio_stream_feedback_thread), stream)
353         }
354 #else
355         if (stream_parameter -> ux_device_class_audio_stream_parameter_feedback_task_function)
356         {
357 
358             /* Save task function for streaming.  */
359             stream -> ux_device_class_audio_stream_feedback_task_function = stream_parameter -> ux_device_class_audio_stream_parameter_feedback_task_function;
360         }
361 #endif
362 #endif
363 
364         /* Save callbacks.  */
365         _ux_utility_memory_copy(&stream -> ux_device_class_audio_stream_callbacks,
366                                 &stream_parameter -> ux_device_class_audio_stream_parameter_callbacks,
367                                 sizeof(UX_DEVICE_CLASS_AUDIO_STREAM_CALLBACKS)); /* Use case of memcpy is verified. */
368 
369         /* Save audio instance.  */
370         stream -> ux_device_class_audio_stream_audio = audio;
371 
372         stream ++;
373         stream_parameter ++;
374     }
375 
376     /* Check for successful creation.  */
377     if (status == UX_SUCCESS)
378     {
379 
380         /* Save the address of the Audio instance inside the Audio container.  */
381         audio_class -> ux_slave_class_instance = (VOID *) audio;
382 
383         /* Link to class instance.  */
384         audio -> ux_device_class_audio_class = audio_class;
385 
386         /* Save callbacks.  */
387         _ux_utility_memory_copy(&audio -> ux_device_class_audio_callbacks,
388             &audio_parameter -> ux_device_class_audio_parameter_callbacks,
389             sizeof(UX_DEVICE_CLASS_AUDIO_CALLBACKS)); /* Use case of memcpy is verified. */
390 
391 #if defined(UX_DEVICE_STANDALONE)
392 
393         /* Link task function.  */
394         audio_class -> ux_slave_class_task_function = _ux_device_class_audio_tasks_run;
395 #endif
396 
397         /* Return completion status.  */
398         return(UX_SUCCESS);
399     }
400 
401     /* Error trap!  */
402     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
403 
404     /* Free allocated resources.  */
405     stream = audio -> ux_device_class_audio_streams;
406     for (i = 0; i < audio -> ux_device_class_audio_streams_nb; i ++)
407     {
408 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
409 #if !defined(UX_DEVICE_STANDALONE)
410         if (stream -> ux_device_class_audio_stream_feedback_thread_stack)
411         {
412             _ux_device_thread_delete(&stream -> ux_device_class_audio_stream_feedback_thread);
413             _ux_utility_memory_free(stream -> ux_device_class_audio_stream_feedback_thread_stack);
414         }
415 #endif
416 #endif
417 #if !defined(UX_DEVICE_STANDALONE)
418         if (stream -> ux_device_class_audio_stream_thread_stack)
419         {
420             _ux_device_thread_delete(&stream -> ux_device_class_audio_stream_thread);
421             _ux_utility_memory_free(stream -> ux_device_class_audio_stream_thread_stack);
422         }
423 #endif
424         if (stream -> ux_device_class_audio_stream_buffer)
425             _ux_utility_memory_free(stream -> ux_device_class_audio_stream_buffer);
426         stream ++;
427     }
428 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
429 #if !defined(UX_DEVICE_STANDALONE)
430     if (audio_class -> ux_slave_class_thread_stack)
431     {
432         _ux_device_thread_delete(&audio_class -> ux_slave_class_thread);
433         _ux_utility_memory_free(audio_class -> ux_slave_class_thread_stack);
434 
435         _ux_device_semaphore_delete(&audio -> ux_device_class_audio_status_semaphore);
436         _ux_device_mutex_delete(&audio -> ux_device_class_audio_status_mutex);
437     }
438 #else
439     if (audio -> ux_device_class_audio_status_queue)
440     {
441         _ux_utility_memory_free(audio -> ux_device_class_audio_status_queue);
442     }
443 #endif
444 #endif
445     _ux_utility_memory_free(audio);
446 
447     return(status);
448 }
449 
450 /**************************************************************************/
451 /*                                                                        */
452 /*  FUNCTION                                               RELEASE        */
453 /*                                                                        */
454 /*    _uxe_device_class_audio_initialize                  PORTABLE C      */
455 /*                                                           6.2.1        */
456 /*  AUTHOR                                                                */
457 /*                                                                        */
458 /*    Chaoqiong Xiao, Microsoft Corporation                               */
459 /*                                                                        */
460 /*  DESCRIPTION                                                           */
461 /*                                                                        */
462 /*    This function checks errors in audio initialization function call.  */
463 /*                                                                        */
464 /*  INPUT                                                                 */
465 /*                                                                        */
466 /*    command                               Pointer to audio command      */
467 /*                                                                        */
468 /*  OUTPUT                                                                */
469 /*                                                                        */
470 /*    Completion Status                                                   */
471 /*                                                                        */
472 /*  CALLS                                                                 */
473 /*                                                                        */
474 /*    _ux_device_class_audio_initialize     Initialize audio instance     */
475 /*                                                                        */
476 /*  CALLED BY                                                             */
477 /*                                                                        */
478 /*    Device Audio Class                                                  */
479 /*                                                                        */
480 /*  RELEASE HISTORY                                                       */
481 /*                                                                        */
482 /*    DATE              NAME                      DESCRIPTION             */
483 /*                                                                        */
484 /*  03-08-2023     Chaoqiong Xiao           Initial Version 6.2.1         */
485 /*                                                                        */
486 /**************************************************************************/
_uxe_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND * command)487 UINT  _uxe_device_class_audio_initialize(UX_SLAVE_CLASS_COMMAND *command)
488 {
489 
490 UX_DEVICE_CLASS_AUDIO_PARAMETER         *audio_parameter;
491 
492     /* Get the pointer to the application parameters for the audio class.  */
493     audio_parameter = (UX_DEVICE_CLASS_AUDIO_PARAMETER *)command -> ux_slave_class_command_parameter;
494 
495     /* Sanity checks.  */
496 
497     /* There must be at least one stream.  */
498     if (audio_parameter -> ux_device_class_audio_parameter_streams == UX_NULL ||
499         audio_parameter -> ux_device_class_audio_parameter_streams_nb < 1)
500         return(UX_INVALID_PARAMETER);
501 
502 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
503 
504     /* There must be status setting for event queue.  */
505     if (audio_parameter -> ux_device_class_audio_parameter_status_queue_size == 0 ||
506         audio_parameter -> ux_device_class_audio_parameter_status_size == 0)
507         return(UX_INVALID_PARAMETER);
508 #endif
509 
510     /* Do initialize.  */
511     return(_ux_device_class_audio_initialize(command));
512 }
513