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_frame_parameters_set           PORTABLE C      */
38 /*                                                           6.1.11       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function sets the video parameters for the video device.       */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    video                                 Pointer to video class        */
50 /*    frame_format                          Video format to use           */
51 /*    width                                 Video frame width             */
52 /*    height                                Video frame height            */
53 /*    frame_interval                        Video frame interval          */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _ux_host_class_video_format_data_get  Get format data               */
62 /*    _ux_host_class_video_frame_data_get   Get frame data                */
63 /*    _ux_host_stack_transfer_request       Process transfer request      */
64 /*    _ux_utility_descriptor_parse          Parse descriptor              */
65 /*    _ux_utility_memory_allocate           Allocate memory block         */
66 /*    _ux_utility_memory_free               Release memory block          */
67 /*    _ux_host_semaphore_get                Get semaphore                 */
68 /*    _ux_host_semaphore_put                Put semaphore                 */
69 /*    _ux_utility_long_get                  Read 32-bit value             */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    Video Class                                                         */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
80 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            resulting in version 6.1    */
82 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            validated 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 /*                                            internal clean up,          */
90 /*                                            fixed standalone compile,   */
91 /*                                            resulting in version 6.1.11 */
92 /*                                                                        */
93 /**************************************************************************/
_ux_host_class_video_frame_parameters_set(UX_HOST_CLASS_VIDEO * video,ULONG frame_format,ULONG width,ULONG height,ULONG frame_interval)94 UINT  _ux_host_class_video_frame_parameters_set(UX_HOST_CLASS_VIDEO *video, ULONG frame_format, ULONG width, ULONG height, ULONG frame_interval)
95 {
96 
97 UX_HOST_CLASS_VIDEO_PARAMETER_FORMAT_DATA       format_parameter;
98 UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA        frame_parameter;
99 UX_HOST_CLASS_VIDEO_FRAME_DESCRIPTOR            frame_descriptor;
100 ULONG                                           format_index;
101 ULONG                                           frame_index;
102 UINT                                            status;
103 ULONG                                           min_frame_interval;
104 ULONG                                           max_frame_interval;
105 ULONG                                           frame_interval_step;
106 ULONG                                           i;
107 UX_ENDPOINT                                     *control_endpoint;
108 UX_TRANSFER                                     *transfer_request;
109 UINT                                            streaming_interface;
110 UCHAR                                           *control_buffer;
111 ULONG                                           max_payload_size;
112 
113 
114     /* Find the requested frame format.  */
115     for (format_index = 1; format_index <= video -> ux_host_class_video_number_formats; format_index++)
116     {
117 
118         /* Get format data for current format index.  */
119         format_parameter.ux_host_class_video_parameter_format_requested = format_index;
120         status = _ux_host_class_video_format_data_get(video, &format_parameter);
121         if (status != UX_SUCCESS)
122         {
123             return(status);
124         }
125 
126         /* Check if the format type is the one requested.  */
127         if (format_parameter.ux_host_class_video_parameter_format_subtype == frame_format)
128         {
129 
130             /* Save number of frames in the video instance.  */
131             video -> ux_host_class_video_number_frames = format_parameter.ux_host_class_video_parameter_number_frame_descriptors;
132 
133             /* The format is found and break the loop.  */
134             break;
135         }
136     }
137 
138     /* Check if the requested format is found.  */
139     if (format_index > video -> ux_host_class_video_number_formats)
140     {
141         return(UX_HOST_CLASS_VIDEO_PARAMETER_ERROR);
142     }
143 
144     /* Find the requested frame resolution.  */
145     for (frame_index = 1; frame_index <= video -> ux_host_class_video_number_frames; frame_index++)
146     {
147 
148         /* Get frame data for current frame index.  */
149         frame_parameter.ux_host_class_video_parameter_frame_requested = frame_index;
150         status = _ux_host_class_video_frame_data_get(video, &frame_parameter);
151         if (status != UX_SUCCESS)
152         {
153             return(status);
154         }
155 
156         /* Check the frame resolution.  */
157         if (frame_parameter.ux_host_class_video_parameter_frame_width == width &&
158             frame_parameter.ux_host_class_video_parameter_frame_height == height)
159         {
160 
161             /* Save the current frame index.  */
162             video -> ux_host_class_video_current_frame = frame_index;
163 
164             /* The requested resolution is found, break the loop.  */
165             break;
166         }
167     }
168 
169     /* Check if the requested resolution is found.  */
170     if (frame_index > video -> ux_host_class_video_number_frames)
171     {
172         return(UX_HOST_CLASS_VIDEO_PARAMETER_ERROR);
173     }
174 
175     /* Make the descriptor machine independent.  */
176     _ux_utility_descriptor_parse(video -> ux_host_class_video_current_frame_address,
177                                  _ux_system_class_video_frame_descriptor_structure,
178                                  UX_HOST_CLASS_VIDEO_FRAME_DESCRIPTOR_ENTRIES, (UCHAR *) &frame_descriptor);
179 
180     /* Initial status for frame interval checking.  */
181     status = UX_HOST_CLASS_VIDEO_PARAMETER_ERROR;
182 
183     /* Check the frame interval type.  */
184     if (frame_descriptor.bFrameIntervalType == 0)
185     {
186 
187         /* Frame interval type is continuous.  */
188         min_frame_interval = _ux_utility_long_get(video -> ux_host_class_video_current_frame_address + 26);
189         max_frame_interval = _ux_utility_long_get(video -> ux_host_class_video_current_frame_address + 30);
190         frame_interval_step = _ux_utility_long_get(video -> ux_host_class_video_current_frame_address + 34);
191 
192         /* Check if the frame interval is valid.  */
193         if (frame_interval >= min_frame_interval && frame_interval <= max_frame_interval &&
194            ((frame_interval_step == 0) ||
195             (frame_interval - min_frame_interval) % frame_interval_step == 0))
196         {
197 
198             /* Save the frame interval.  */
199             video -> ux_host_class_video_current_frame_interval = frame_interval;
200             status = UX_SUCCESS;
201         }
202     }
203     else
204     {
205 
206         /* Frame interval type is discrete.  */
207         for(i = 0; i < frame_descriptor.bFrameIntervalType; i++)
208         {
209 
210             /* Check if the requested frame interval is valid.  */
211             if (frame_interval == _ux_utility_long_get(video -> ux_host_class_video_current_frame_address + 26 + i * sizeof(ULONG)))
212             {
213 
214                 /* Save the frame interval.  */
215                 video -> ux_host_class_video_current_frame_interval = frame_interval;
216                 status = UX_SUCCESS;
217             }
218         }
219     }
220 
221     if (status != UX_SUCCESS)
222         return(UX_HOST_CLASS_VIDEO_PARAMETER_ERROR);
223 
224     /* Protect thread reentry to this instance.  */
225     status =  _ux_host_semaphore_get(&video -> ux_host_class_video_semaphore, UX_WAIT_FOREVER);
226     if (status != UX_SUCCESS)
227         return(status);
228 
229     /* We need to get the default control endpoint transfer request pointer.  */
230     control_endpoint =  &video -> ux_host_class_video_device -> ux_device_control_endpoint;
231     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
232 
233     /* Get the interface number of the video streaming interface.  */
234     streaming_interface =  video -> ux_host_class_video_streaming_interface -> ux_interface_descriptor.bInterfaceNumber;
235 
236     /* Need to allocate memory for the control_buffer.  */
237     control_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH);
238     if (control_buffer == UX_NULL)
239     {
240 
241         /* Unprotect thread reentry to this instance.  */
242         _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
243 
244         /* Return error.  */
245         return(UX_MEMORY_INSUFFICIENT);
246     }
247 
248     *(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_FORMAT_INDEX) = (UCHAR)format_index;
249     *(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_FRAME_INDEX) = (UCHAR)frame_index;
250     _ux_utility_long_put(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_FRAME_INTERVAL, frame_interval);
251 
252     /* Create a transfer request for the SET_CUR buffer request.  */
253     transfer_request -> ux_transfer_request_data_pointer =      control_buffer;
254     transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH;
255     transfer_request -> ux_transfer_request_function =          UX_HOST_CLASS_VIDEO_SET_CUR;
256     transfer_request -> ux_transfer_request_type =              UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
257     transfer_request -> ux_transfer_request_value =             UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL << 8;
258     transfer_request -> ux_transfer_request_index =             streaming_interface;
259 
260     /* Send request to HCD layer.  */
261     status =  _ux_host_stack_transfer_request(transfer_request);
262 
263     /* Check for correct transfer. Buffer may not be all what we asked for.  */
264     if (status == UX_SUCCESS)
265     {
266 
267 
268         /* Create a transfer request for the GET_CUR buffer request.  */
269         transfer_request -> ux_transfer_request_data_pointer =      control_buffer;
270         transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_VIDEO_PROBE_COMMIT_LENGTH;
271         transfer_request -> ux_transfer_request_function =          UX_HOST_CLASS_VIDEO_GET_CUR;
272         transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
273         transfer_request -> ux_transfer_request_value =             UX_HOST_CLASS_VIDEO_VS_PROBE_CONTROL << 8;
274         transfer_request -> ux_transfer_request_index =             streaming_interface;
275 
276         /* Send request to HCD layer.  */
277         status =  _ux_host_stack_transfer_request(transfer_request);
278 
279     }
280 
281     /* Get the max payload transfer size returned from video device.  */
282     max_payload_size = _ux_utility_long_get(control_buffer + UX_HOST_CLASS_VIDEO_PROBE_COMMIT_MAX_PAYLOAD_TRANSFER_SIZE);
283 
284     /* Validate if the payload size is inside isochronouse packet payload.  */
285     if (max_payload_size == 0)
286         status = UX_HOST_CLASS_VIDEO_PARAMETER_ERROR;
287     else
288     {
289         if (video -> ux_host_class_video_device -> ux_device_speed != UX_HIGH_SPEED_DEVICE)
290         {
291             if (max_payload_size > 1023)
292                 status = UX_HOST_CLASS_VIDEO_PARAMETER_ERROR;
293         }
294         else
295         {
296             if (max_payload_size > (1024 * 3))
297                 status = UX_HOST_CLASS_VIDEO_PARAMETER_ERROR;
298         }
299     }
300 
301     /* Free all used resources.  */
302     _ux_utility_memory_free(control_buffer);
303 
304     /* Unprotect thread reentry to this instance.  */
305     _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
306 
307     /* Check the transfer status.  */
308     if (status == UX_SUCCESS)
309     {
310 
311         /* Save the maximum payload size returned by the device.  */
312         video -> ux_host_class_video_current_max_payload_size = max_payload_size;
313         return(UX_SUCCESS);
314     }
315     else
316     {
317 
318         /* The probe process failed. Return error.  */
319         return(UX_HOST_CLASS_VIDEO_PARAMETER_ERROR);
320     }
321 }
322 
323