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 /** USBX Component                                                        */
14 /**                                                                       */
15 /**   Device Audio Class                                                  */
16 /**                                                                       */
17 /**************************************************************************/
18 /**************************************************************************/
19 
20 #define UX_SOURCE_CODE
21 
22 
23 /* Include necessary system files.  */
24 
25 #include "ux_api.h"
26 #include "ux_device_class_audio.h"
27 #include "ux_device_stack.h"
28 
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _ux_device_class_audio_activate                     PORTABLE C      */
35 /*                                                           6.3.0        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Chaoqiong Xiao, Microsoft Corporation                               */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function initializes the USB Audio device.                     */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    command                               Pointer to audio command      */
47 /*                                                                        */
48 /*  OUTPUT                                                                */
49 /*                                                                        */
50 /*    Completion Status                                                   */
51 /*                                                                        */
52 /*  CALLS                                                                 */
53 /*                                                                        */
54 /*    _ux_system_error_handler              System error trap             */
55 /*                                                                        */
56 /*  CALLED BY                                                             */
57 /*                                                                        */
58 /*    Device Audio Class                                                  */
59 /*                                                                        */
60 /*  RELEASE HISTORY                                                       */
61 /*                                                                        */
62 /*    DATE              NAME                      DESCRIPTION             */
63 /*                                                                        */
64 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
65 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
66 /*                                            resulting in version 6.1    */
67 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
68 /*                                            fixed parameter/variable    */
69 /*                                            names conflict C++ keyword, */
70 /*                                            added interrupt support,    */
71 /*                                            resulting in version 6.1.12 */
72 /*  10-31-2022     Yajun Xia                Modified comment(s),          */
73 /*                                            added standalone support,   */
74 /*                                            resulting in version 6.2.0  */
75 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            added a new mode to manage  */
77 /*                                            endpoint buffer in classes  */
78 /*                                            with zero copy enabled,     */
79 /*                                            resulting in version 6.3.0  */
80 /*                                                                        */
81 /**************************************************************************/
_ux_device_class_audio_activate(UX_SLAVE_CLASS_COMMAND * command)82 UINT  _ux_device_class_audio_activate(UX_SLAVE_CLASS_COMMAND *command)
83 {
84 
85 UX_SLAVE_DEVICE                         *device;
86 UX_SLAVE_INTERFACE                      *audio_interface;
87 UX_SLAVE_INTERFACE                      *control_interface;
88 UX_SLAVE_INTERFACE                      *stream_interface;
89 UX_DEVICE_CLASS_AUDIO                   *audio;
90 UX_DEVICE_CLASS_AUDIO_STREAM            *stream;
91 UX_SLAVE_CLASS                          *audio_class;
92 ULONG                                    stream_index;
93 
94 
95     /* Get the class container.  */
96     audio_class =  command -> ux_slave_class_command_class_ptr;
97 
98     /* Get the class instance in the container.  */
99     audio = (UX_DEVICE_CLASS_AUDIO *) audio_class -> ux_slave_class_instance;
100 
101     /* Get the interface that owns this instance.  */
102     audio_interface =  (UX_SLAVE_INTERFACE  *) command -> ux_slave_class_command_interface;
103 
104     /* Get the device instance.  */
105     device = &_ux_system_slave -> ux_system_slave_device;
106     audio -> ux_device_class_audio_device = device;
107 
108     /* We only support audio interface here.  */
109     if (audio_interface -> ux_slave_interface_descriptor.bInterfaceClass != UX_DEVICE_CLASS_AUDIO_CLASS)
110         return(UX_NO_CLASS_MATCH);
111 
112     /* It's control interface?  */
113     if (audio_interface -> ux_slave_interface_descriptor.bInterfaceSubClass == UX_DEVICE_CLASS_AUDIO_SUBCLASS_CONTROL)
114     {
115 
116         /* Store the interface in the class instance.  */
117         audio -> ux_device_class_audio_interface = audio_interface;
118 
119         /* Store the class instance into the interface.  */
120         audio_interface -> ux_slave_interface_class_instance = (VOID *)audio;
121 
122 #if defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
123 
124         /* Find interrupt endpoint (only endpoint in this AC interface).  */
125         audio -> ux_device_class_audio_interrupt = audio_interface -> ux_slave_interface_first_endpoint;
126         audio -> ux_device_class_audio_status_queued = 0;
127         audio -> ux_device_class_audio_status_head = audio -> ux_device_class_audio_status_queue;
128         audio -> ux_device_class_audio_status_tail = audio -> ux_device_class_audio_status_queue;
129 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
130         if (audio -> ux_device_class_audio_interrupt)
131             audio -> ux_device_class_audio_interrupt ->
132                 ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
133                                 audio -> ux_device_class_audio_interrupt_buffer;
134 #endif
135 #endif
136     }
137     else
138     {
139 
140         /* It's streaming interface.  */
141         stream_interface = audio_interface;
142 
143         /* Separate driver for each interface (IAD not used)?  */
144         if (audio -> ux_device_class_audio_interface == UX_NULL)
145         {
146 
147             /* Always use just 1 stream for 1 interface.  */
148             stream_index = 0;
149         }
150 
151         /* Re-use the same driver (IAD used)?  */
152         else
153         {
154 
155             /* Re-use saved control interface.  */
156             control_interface = audio -> ux_device_class_audio_interface;
157 
158             /* Calculate stream index.  */
159             stream_index  = stream_interface -> ux_slave_interface_descriptor.bInterfaceNumber;
160             stream_index -= control_interface -> ux_slave_interface_descriptor.bInterfaceNumber;
161             stream_index --;
162 
163         }
164 
165         /* Sanity check.  */
166         if (stream_index >= audio -> ux_device_class_audio_streams_nb)
167         {
168 
169             /* Error trap!  */
170             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
171             return(UX_MEMORY_INSUFFICIENT);
172         }
173 
174         /* Locate stream based on interface number.  */
175         stream = &audio -> ux_device_class_audio_streams[stream_index];
176 
177         /* Store the interface for the stream.  */
178         stream -> ux_device_class_audio_stream_interface = stream_interface;
179 
180         /* Store the class instance into the interface.  */
181         stream_interface -> ux_slave_interface_class_instance = (VOID *)audio;
182 #if defined(UX_DEVICE_STANDALONE)
183 
184         /* Reset stream task state.  */
185         stream -> ux_device_class_audio_stream_task_state = UX_STATE_RESET;
186         stream -> ux_device_class_audio_stream_task_state = UX_SUCCESS;
187 #endif
188     }
189 
190     /* If there is a activate function call it.  */
191     if (audio -> ux_device_class_audio_callbacks.ux_slave_class_audio_instance_activate != UX_NULL)
192     {
193 
194         /* Invoke the application.  */
195         audio -> ux_device_class_audio_callbacks.ux_slave_class_audio_instance_activate(audio);
196     }
197 
198     /* Return completion status.  */
199     return(UX_SUCCESS);
200 }
201 
202