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_change                       PORTABLE C      */
36 /*                                                           6.2.0        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function changes the interface of the 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_system_error_handler          System error trap                 */
56 /*                                                                        */
57 /*  CALLED BY                                                             */
58 /*                                                                        */
59 /*    Device Audio Class                                                  */
60 /*                                                                        */
61 /*  RELEASE HISTORY                                                       */
62 /*                                                                        */
63 /*    DATE              NAME                      DESCRIPTION             */
64 /*                                                                        */
65 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
66 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
67 /*                                            resulting in version 6.1    */
68 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
69 /*                                            replaced wMaxPacketSize by  */
70 /*                                            calculated payload size,    */
71 /*                                            resulting in version 6.1.9  */
72 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
73 /*                                            added feedback support,     */
74 /*                                            resulting in version 6.1.10 */
75 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            fixed standalone compile,   */
77 /*                                            resulting in version 6.1.11 */
78 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            fixed parameter/variable    */
80 /*                                            names conflict C++ keyword, */
81 /*                                            rx full packet for          */
82 /*                                            feedback,                   */
83 /*                                            resulting in version 6.1.12 */
84 /*  10-31-2022     Yajun Xia                Modified comment(s),          */
85 /*                                            added standalone support,   */
86 /*                                            resulting in version 6.2.0  */
87 /*                                                                        */
88 /**************************************************************************/
_ux_device_class_audio_change(UX_SLAVE_CLASS_COMMAND * command)89 UINT  _ux_device_class_audio_change(UX_SLAVE_CLASS_COMMAND *command)
90 {
91 
92 UX_DEVICE_CLASS_AUDIO                   *audio;
93 UX_DEVICE_CLASS_AUDIO_STREAM            *stream;
94 UX_SLAVE_CLASS                          *class_ptr;
95 UX_SLAVE_INTERFACE                      *interface_ptr;
96 UX_SLAVE_ENDPOINT                       *endpoint;
97 UCHAR                                   *frame_buffer;
98 ULONG                                    stream_index;
99 ULONG                                    endpoint_dir;
100 
101 
102     /* Get the class container.  */
103     class_ptr =  command -> ux_slave_class_command_class_ptr;
104 
105     /* Get the class instance in the container.  */
106     audio = (UX_DEVICE_CLASS_AUDIO *) class_ptr -> ux_slave_class_instance;
107 
108     /* Get the interface that owns this instance.  */
109     interface_ptr =  (UX_SLAVE_INTERFACE  *) command -> ux_slave_class_command_interface;
110 
111     /* Get the interface number (base 0).  */
112     if (audio -> ux_device_class_audio_interface)
113     {
114 
115         /* If IAD used, calculate stream index based on interface number.  */
116         stream_index  = interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber;
117         stream_index -= audio -> ux_device_class_audio_interface -> ux_slave_interface_descriptor.bInterfaceNumber;
118         stream_index --;
119     }
120     else
121 
122         /* One stream for one driver!  */
123         stream_index  = 0;
124 
125     /* Get the stream instance.  */
126     stream = &audio -> ux_device_class_audio_streams[stream_index];
127 
128     /* Update the interface.  */
129     stream -> ux_device_class_audio_stream_interface = interface_ptr;
130 
131     /* If the interface to mount has a non zero alternate setting, the class is really active with
132        the endpoints active.  If the interface reverts to alternate setting 0, it needs to have
133        the pending transactions terminated.  */
134     if (interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting != 0)
135     {
136 
137         /* Locate the endpoints.  ISO IN(write)/OUT(read) for Streaming Interface.  */
138         endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
139 
140         /* Parse all endpoints.  */
141 #if defined(UX_DEVICE_STANDALONE)
142 
143         endpoint_dir = (stream -> ux_device_class_audio_stream_task_function ==
144                         _ux_device_class_audio_read_task_function) ?
145                         UX_ENDPOINT_OUT: UX_ENDPOINT_IN;
146 #else
147 
148         endpoint_dir = (stream -> ux_device_class_audio_stream_thread.tx_thread_entry ==
149                         _ux_device_class_audio_read_thread_entry) ?
150                         UX_ENDPOINT_OUT : UX_ENDPOINT_IN;
151 #endif
152         stream -> ux_device_class_audio_stream_endpoint = UX_NULL;
153 
154 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
155         stream -> ux_device_class_audio_stream_feedback = UX_NULL;
156 #endif
157         while(endpoint != UX_NULL)
158         {
159 
160             /* Check the endpoint attributes.  */
161             if((endpoint -> ux_slave_endpoint_descriptor.bmAttributes &
162                 UX_DEVICE_CLASS_AUDIO_EP_TRANSFER_TYPE_MASK) == UX_ISOCHRONOUS_ENDPOINT)
163             {
164 
165                 /* Check the endpoint direction.  */
166                 if ((endpoint->ux_slave_endpoint_descriptor.bEndpointAddress &
167                      UX_ENDPOINT_DIRECTION) == endpoint_dir)
168                 {
169 
170                     /* We found the data endpoint, check its size.  */
171                     if (endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_transfer_length > stream -> ux_device_class_audio_stream_frame_buffer_size - 8)
172                     {
173 
174                         /* Error trap!  */
175                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
176 
177                         /* Frame buffer too small for endpoints.  */
178                         return(UX_MEMORY_INSUFFICIENT);
179                     }
180 
181                     /* Save it.  */
182                     stream -> ux_device_class_audio_stream_endpoint = endpoint;
183                 }
184 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
185                 else
186                 {
187 
188                     /* We found the feedback endpoint, check its size.  */
189                     if (endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_transfer_length <
190                         (_ux_system_slave->ux_system_slave_speed == UX_HIGH_SPEED_DEVICE ? 4 : 3))
191                     {
192 
193                         /* Error trap!  */
194                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
195 
196                         /* Frame buffer too small for endpoints.  */
197                         return(UX_MEMORY_INSUFFICIENT);
198                     }
199 
200                     /* Set request length, uses full packet for OUT to avoid possible overflow.  */
201                     endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length =
202                         endpoint_dir == UX_ENDPOINT_OUT ?
203                         endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_transfer_length :
204                         ((_ux_system_slave -> ux_system_slave_speed == UX_HIGH_SPEED_DEVICE) ?
205                          UX_FEEDBACK_SIZE_HIGH_SPEED : UX_FEEDBACK_SIZE_FULL_SPEED);
206 
207                     /* Save it.  */
208                     stream -> ux_device_class_audio_stream_feedback = endpoint;
209                 }
210 #endif
211             }
212 
213             /* Check if done.  */
214             if (stream -> ux_device_class_audio_stream_endpoint
215 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
216                 && stream -> ux_device_class_audio_stream_feedback
217 #endif
218                 )
219                 break;
220 
221             /* Next endpoint.  */
222             endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
223         }
224 
225         /* Now check if all endpoints have been found.  */
226         if (stream -> ux_device_class_audio_stream_endpoint == UX_NULL)
227         {
228 
229             /* Error trap!  */
230             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
231 
232             /* Not all endpoints have been found. Major error, do not proceed.  */
233             return(UX_DESCRIPTOR_CORRUPTED);
234         }
235 
236 #if defined(UX_DEVICE_STANDALONE)
237 
238         /* Reset background transfer state.  */
239         stream -> ux_device_class_audio_stream_task_state = UX_STATE_RESET;
240 #endif
241 
242         /* Now reset payload buffer error count.  */
243         stream -> ux_device_class_audio_stream_buffer_error_count = 0;
244 
245         /* Now reset frame buffers.  */
246         frame_buffer = stream -> ux_device_class_audio_stream_buffer;
247         while(frame_buffer < stream -> ux_device_class_audio_stream_buffer + stream -> ux_device_class_audio_stream_buffer_size)
248         {
249 
250             /* Reset header information.  */
251             *((ULONG *) frame_buffer     ) = 0;
252             *((ULONG *)(frame_buffer + 4)) = 0;
253 
254             /* Next.  */
255             frame_buffer += stream -> ux_device_class_audio_stream_frame_buffer_size;
256         }
257         stream -> ux_device_class_audio_stream_transfer_pos = stream -> ux_device_class_audio_stream_access_pos;
258 
259 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT) && !defined(UX_DEVICE_STANDALONE)
260 
261         /* If feedback supported, resume the thread.  */
262         if (stream -> ux_device_class_audio_stream_feedback_thread_stack)
263             _ux_utility_thread_resume(&stream -> ux_device_class_audio_stream_feedback_thread);
264 #endif
265     }
266     else
267     {
268 
269         /* There is no data endpoint.  */
270         stream -> ux_device_class_audio_stream_endpoint = UX_NULL;
271 #if defined(UX_DEVICE_CLASS_AUDIO_FEEDBACK_SUPPORT)
272         stream -> ux_device_class_audio_stream_feedback = UX_NULL;
273 #endif
274 
275         /* In this case, we are reverting to the Alternate Setting 0.  We need to terminate the pending transactions.  */
276         /* Endpoints actually aborted and destroyed before change command.  */
277         /*
278         _ux_device_stack_transfer_all_request_abort(stream -> ux_device_class_audio_stream_endpoint, UX_TRANSFER_APPLICATION_RESET);
279          */
280     }
281 
282     /* Invoke stream change callback.  */
283     if (stream -> ux_device_class_audio_stream_callbacks.ux_device_class_audio_stream_change)
284         stream -> ux_device_class_audio_stream_callbacks.ux_device_class_audio_stream_change(stream, interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting);
285 
286     /* Return completion status.  */
287     return(UX_SUCCESS);
288 }
289