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 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** Video Class */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_host_class_video.h"
30 #include "ux_host_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_video_channel_start PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function starts the video channel. */
46 /* */
47 /* INPUT */
48 /* */
49 /* video Pointer to video class */
50 /* channel_parameter Pointer to video channel */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Completion Status */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_host_class_video_alternate_setting_locate */
59 /* Search alternate setting */
60 /* _ux_host_stack_interface_setting_select */
61 /* Select alternate setting */
62 /* _ux_host_stack_interface_endpoint_get Get interface endpoint */
63 /* _ux_host_stack_transfer_request Process transfer request */
64 /* _ux_host_semaphore_get Get semaphore */
65 /* _ux_host_semaphore_put Release semaphore */
66 /* _ux_utility_memory_allocate Allocate memory block */
67 /* _ux_utility_memory_free Release memory block */
68 /* _ux_utility_long_get Get 32-bit value */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* Video Class */
73 /* */
74 /* RELEASE HISTORY */
75 /* */
76 /* DATE NAME DESCRIPTION */
77 /* */
78 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
79 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
80 /* resulting in version 6.1 */
81 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
82 /* fixed bandwidth check, */
83 /* saved max payload size, */
84 /* resulting in version 6.1.9 */
85 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
86 /* refined macros names, */
87 /* resulting in version 6.1.10 */
88 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
89 /* fixed standalone compile, */
90 /* resulting in version 6.1.11 */
91 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
92 /* fixed parameter/variable */
93 /* names conflict C++ keyword, */
94 /* resulting in version 6.1.12 */
95 /* */
96 /**************************************************************************/
_ux_host_class_video_channel_start(UX_HOST_CLASS_VIDEO * video,UX_HOST_CLASS_VIDEO_PARAMETER_CHANNEL * video_parameter)97 UINT _ux_host_class_video_channel_start(UX_HOST_CLASS_VIDEO *video, UX_HOST_CLASS_VIDEO_PARAMETER_CHANNEL *video_parameter)
98 {
99
100 UX_ENDPOINT *control_endpoint;
101 UX_TRANSFER *transfer_request;
102 UINT status;
103 UCHAR *control_buffer;
104 UINT alternate_setting;
105 UX_CONFIGURATION *configuration;
106 UX_INTERFACE *interface_ptr;
107 UX_ENDPOINT *endpoint;
108 ULONG endpoint_index;
109 UINT streaming_interface;
110 UINT max_payload_size;
111
112
113 /* Protect thread reentry to this instance. */
114 status = _ux_host_semaphore_get(&video -> ux_host_class_video_semaphore, UX_WAIT_FOREVER);
115
116 /* We need to get the default control endpoint transfer request pointer. */
117 control_endpoint = &video -> ux_host_class_video_device -> ux_device_control_endpoint;
118 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
119
120 /* Get the interface number of the video streaming interface. */
121 streaming_interface = video -> ux_host_class_video_streaming_interface -> ux_interface_descriptor.bInterfaceNumber;
122
123 /* Need to allocate memory for the control_buffer. */
124 control_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH);
125 if (control_buffer == UX_NULL)
126 {
127
128 /* Unprotect thread reentry to this instance. */
129 _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
130
131 /* Return error. */
132 return(UX_MEMORY_INSUFFICIENT);
133 }
134
135 /* Check the result, did we find the alternate setting ? */
136 if (status == UX_SUCCESS)
137 {
138
139 *(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_FORMAT_INDEX) = (UCHAR)video_parameter -> ux_host_class_video_parameter_format_requested;
140 *(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_FRAME_INDEX) = (UCHAR)video_parameter -> ux_host_class_video_parameter_frame_requested;
141 _ux_utility_long_put(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_FRAME_INTERVAL,
142 video_parameter -> ux_host_class_video_parameter_frame_interval_requested);
143
144 /* Create a transfer request for the GET_CUR_buffer request. */
145 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
146 transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH;
147 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_VIDEO_SET_CUR;
148 transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
149 transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL << 8;
150 transfer_request -> ux_transfer_request_index = streaming_interface;
151
152 /* Send request to HCD layer. */
153 status = _ux_host_stack_transfer_request(transfer_request);
154
155 /* Check for correct transfer. Buffer may not be all what we asked for. */
156 if (status == UX_SUCCESS)
157 {
158
159
160 /* Create a transfer request for the SET_CUR_buffer request. */
161 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
162 transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH;
163 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_VIDEO_GET_CUR;
164 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
165 transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL << 8;
166 transfer_request -> ux_transfer_request_index = streaming_interface;
167
168 /* Send request to HCD layer. */
169 status = _ux_host_stack_transfer_request(transfer_request);
170
171 /* Check for correct transfer. */
172 if (status == UX_SUCCESS)
173 {
174
175 /* We did the GET_CUR and SET_CUR for Probe Control. Now we can commit to the bandwidth. */
176 /* Create a transfer request for the SET_CUR_buffer request. */
177 transfer_request -> ux_transfer_request_data_pointer = control_buffer;
178 transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH;
179 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_VIDEO_SET_CUR;
180 transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
181 transfer_request -> ux_transfer_request_value = UX_HOST_CLASS_VIDEO_VS_COMMIT_CONTROL << 8;
182 transfer_request -> ux_transfer_request_index = streaming_interface;
183
184 /* Send request to HCD layer. */
185 status = _ux_host_stack_transfer_request(transfer_request);
186
187 /* Check for correct transfer. */
188 if (status == UX_SUCCESS)
189 {
190
191 /* Check if user has request specific bandwidth selection. */
192 if (video_parameter -> ux_host_class_video_parameter_channel_bandwidth_selection == 0)
193 {
194
195 /* Get the max payload transfer size returned from video device. */
196 max_payload_size = _ux_utility_long_get(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_MAX_PAYLOAD_TRANSFER_SIZE);
197 }
198 else
199 {
200
201 /* Set the max payload transfer size to the user requested one. */
202 max_payload_size = video_parameter -> ux_host_class_video_parameter_channel_bandwidth_selection;
203 }
204
205 /* Search for the non zero alternate setting of the video stream. */
206 status = _ux_host_class_video_alternate_setting_locate(video, max_payload_size, &alternate_setting);
207
208 if (status == UX_SUCCESS)
209 {
210
211 /* Now the Commit has been done, the alternate setting can be requested. */
212 /* We found the alternate setting for the sampling values demanded, now we need
213 to search its container. */
214 configuration = video -> ux_host_class_video_streaming_interface -> ux_interface_configuration;
215 interface_ptr = configuration -> ux_configuration_first_interface;
216
217 /* Scan all interfaces. */
218 while (interface_ptr != UX_NULL)
219 {
220
221 /* We search for both the right interface and alternate setting. */
222 if ((interface_ptr -> ux_interface_descriptor.bInterfaceNumber == streaming_interface) &&
223 (interface_ptr -> ux_interface_descriptor.bAlternateSetting == alternate_setting))
224 {
225
226 /* We have found the right interface/alternate setting combination
227 The stack will select it for us. */
228 status = _ux_host_stack_interface_setting_select(interface_ptr);
229
230 /* If the alternate setting for the streaming interface could be selected, we memorize it. */
231 if (status == UX_SUCCESS)
232 {
233
234 /* Memorize the interface. */
235 video -> ux_host_class_video_streaming_interface = interface_ptr;
236
237 /* We need to research the isoch endpoint now. */
238 for (endpoint_index = 0; endpoint_index < interface_ptr -> ux_interface_descriptor.bNumEndpoints; endpoint_index++)
239 {
240
241 /* Get the list of endpoints one by one. */
242 status = _ux_host_stack_interface_endpoint_get(video -> ux_host_class_video_streaming_interface,
243 endpoint_index, &endpoint);
244
245 /* Check completion status. */
246 if (status == UX_SUCCESS)
247 {
248
249 /* Check if endpoint is ISOCH, regardless of the direction. */
250 if ((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_ISOCHRONOUS_ENDPOINT)
251 {
252
253 /* We have found the isoch endpoint, save it. */
254 video -> ux_host_class_video_isochronous_endpoint = endpoint;
255
256 /* Save the max payload size.
257 It's not exceeding endpoint bandwidth since the interface alternate
258 setting is located by max payload size. */
259 video -> ux_host_class_video_current_max_payload_size = max_payload_size;
260
261 /* Free all used resources. */
262 _ux_utility_memory_free(control_buffer);
263
264 /* Unprotect thread reentry to this instance. */
265 _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
266
267 /* Return successful completion. */
268 return(UX_SUCCESS);
269 }
270 }
271 }
272 }
273 }
274
275 /* Move to next interface. */
276 interface_ptr = interface_ptr -> ux_interface_next_interface;
277 }
278 }
279 }
280 }
281 }
282 }
283 /* Free all used resources. */
284 _ux_utility_memory_free(control_buffer);
285
286 /* Unprotect thread reentry to this instance. */
287 _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
288
289 /* Return completion status. */
290 return(status);
291 }
292
293