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