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