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 UCHAR _ux_system_class_video_interface_descriptor_structure[] =             {1,1,1,1,1,1,1,1};
33 UCHAR _ux_system_class_video_input_terminal_descriptor_structure[] =        {1,1,1,1,2,1,1};
34 UCHAR _ux_system_class_video_input_header_descriptor_structure[] =          {1,1,1,1,2,1,1,1,1,1,1,1};
35 UCHAR _ux_system_class_video_processing_unit_descriptor_structure[] =       {1,1,1,1,1,2,1,1};
36 UCHAR _ux_system_class_video_streaming_interface_descriptor_structure[] =   {1,1,1,1,1,1};
37 UCHAR _ux_system_class_video_streaming_endpoint_descriptor_structure[] =    {1,1,1,1,1,1};
38 UCHAR _ux_system_class_video_frame_descriptor_structure[] =                 {1,1,1,1,1,2,2,4,4,4,4,1};
39 
40 UCHAR _ux_system_host_class_video_name[] =                                  "ux_host_class_video";
41 
42 typedef struct UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_STRUCT
43 {
44     UX_HOST_CLASS_VIDEO         *video;
45     ULONG                        parsed_flags;
46 } UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER;
47 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_HEADER       1
48 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_IT           2
49 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_PU           4
50 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VS_HEADER       8
51 #define UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_DONE            (1|2|4|8)
52 
53 
_ux_host_class_video_descriptors_parser(VOID * arg,UCHAR * packed_interface_descriptor,UCHAR * packed_entity_descriptor)54 static UINT _ux_host_class_video_descriptors_parser(VOID  *arg,
55                               UCHAR *packed_interface_descriptor,
56                               UCHAR *packed_entity_descriptor)
57 {
58 
59 UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER  *parser;
60 UX_HOST_CLASS_VIDEO                     *video;
61 UX_INTERFACE                            *streaming_interface;
62 UCHAR                                   bInCollection;
63 UCHAR                                   *baInterfaceNr;
64 
65     /* Get parse data.  */
66     parser = (UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER *)arg;
67 
68     /* Get video instance.  */
69     video = parser -> video;
70 
71     if (packed_interface_descriptor[6] == UX_HOST_CLASS_VIDEO_SUBCLASS_CONTROL)
72     {
73 
74         /* Parse VC descriptors.  */
75 
76         /* Locate control interface.  */
77         if (video -> ux_host_class_video_control_interface_number == 0xFF)
78         {
79 
80             /* Parse header.  */
81             if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VC_HEADER)
82             {
83 
84                 /* Get streaming interface.  */
85                 streaming_interface = video -> ux_host_class_video_streaming_interface;
86 
87                 /* Check if this the VC interface is expected.  */
88                 bInCollection = packed_entity_descriptor[11];
89                 baInterfaceNr = packed_entity_descriptor + 12;
90 
91                 /* Validation:
92                  * baInterfaceNr not exceeding current descriptor.
93                  */
94                 if (packed_entity_descriptor[0] + packed_entity_descriptor < baInterfaceNr + bInCollection)
95                     return(1);
96 
97                 while(bInCollection)
98                 {
99 
100                     /* Streaming interface belongs to this control interface.  */
101                     if (*baInterfaceNr == streaming_interface -> ux_interface_descriptor.bInterfaceNumber)
102                     {
103                         video -> ux_host_class_video_control_interface_number = packed_interface_descriptor[2];
104                         parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_HEADER;
105                         return(0);
106                     }
107 
108                     /* Next interface number in descriptor.  */
109                     baInterfaceNr ++;
110                     bInCollection --;
111                 }
112             }
113 
114             /* Not expected interface, just try next descriptor.  */
115             return(0);
116         }
117         else if (packed_interface_descriptor[2] == video -> ux_host_class_video_control_interface_number)
118         {
119 
120             /* It's the expected VC interface.  */
121 
122             /* Parse UX_HOST_CLASS_VIDEO_VC_PROCESSING_UNIT as feature_unit_id.  */
123             if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VC_PROCESSING_UNIT &&
124                 video -> ux_host_class_video_feature_unit_id == 0)
125             {
126                 parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_PU;
127 
128                 /* Save as feature unit ID.  */
129                 video -> ux_host_class_video_feature_unit_id = packed_entity_descriptor[3];
130             }
131 
132             /* Parse UX_HOST_CLASS_VIDEO_VC_INPUT_TERMINAL and type (first only).  */
133             if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VC_INPUT_TERMINAL &&
134                 video -> ux_host_class_video_terminal_id == 0)
135             {
136                 parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VC_IT;
137 
138                 /* Save the video terminal ID.  */
139                 video -> ux_host_class_video_terminal_id = packed_entity_descriptor[3];
140 
141                 /* Save the video terminal type.  */
142                 video -> ux_host_class_video_terminal_type = _ux_utility_short_get(packed_entity_descriptor + 4);
143             }
144         }
145     }
146     else
147     {
148 
149         /* Parse VS descriptors.  */
150         if (packed_entity_descriptor[2] == UX_HOST_CLASS_VIDEO_VS_INPUT_HEADER)
151         {
152             parser -> parsed_flags |= UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_VS_HEADER;
153 
154             /* Get the number of formats.  */
155             video -> ux_host_class_video_number_formats = packed_entity_descriptor[3];
156 
157             /* Get the length of formats.  */
158             video -> ux_host_class_video_length_formats = _ux_utility_short_get(packed_entity_descriptor + 4);
159 
160             /* Save the descriptor where the formats reside.  */
161             video -> ux_host_class_video_format_address = packed_entity_descriptor;
162         }
163     }
164     return(0);
165 }
166 
167 
168 /**************************************************************************/
169 /*                                                                        */
170 /*  FUNCTION                                               RELEASE        */
171 /*                                                                        */
172 /*    _ux_host_class_video_activate                       PORTABLE C      */
173 /*                                                           6.2.0        */
174 /*  AUTHOR                                                                */
175 /*                                                                        */
176 /*    Chaoqiong Xiao, Microsoft Corporation                               */
177 /*                                                                        */
178 /*  DESCRIPTION                                                           */
179 /*                                                                        */
180 /*     This function activates the video class. It may be called twice by */
181 /*     the same device if there is a video control interface to this      */
182 /*     device.                                                            */
183 /*                                                                        */
184 /*  INPUT                                                                 */
185 /*                                                                        */
186 /*    command                               Pointer to command            */
187 /*                                                                        */
188 /*  OUTPUT                                                                */
189 /*                                                                        */
190 /*    Completion Status                                                   */
191 /*                                                                        */
192 /*  CALLS                                                                 */
193 /*                                                                        */
194 /*    _ux_host_class_video_configure        Configure the video class     */
195 /*    _ux_host_class_video_descriptor_get   Get video descriptor          */
196 /*    _ux_host_class_video_input_terminal_get                             */
197 /*                                          Get input terminal            */
198 /*    _ux_host_class_video_input_format_get Get input format              */
199 /*    _ux_host_class_video_control_list_get Get controls                  */
200 /*    _ux_host_stack_class_instance_create  Create class instance         */
201 /*    _ux_host_stack_class_instance_destroy Destroy class instance        */
202 /*    _ux_utility_memory_allocate           Allocate a memory block       */
203 /*    _ux_utility_memory_free               Free a memory block           */
204 /*    _ux_host_semaphore_create             Create protection semaphore   */
205 /*                                                                        */
206 /*  CALLED BY                                                             */
207 /*                                                                        */
208 /*    Video Class                                                         */
209 /*                                                                        */
210 /*  RELEASE HISTORY                                                       */
211 /*                                                                        */
212 /*    DATE              NAME                      DESCRIPTION             */
213 /*                                                                        */
214 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
215 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
216 /*                                            used entities parsing API,  */
217 /*                                            created new semaphore to    */
218 /*                                            protect control requests,   */
219 /*                                            resulting in version 6.1    */
220 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
221 /*                                            refined macros names,       */
222 /*                                            resulting in version 6.1.10 */
223 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
224 /*                                            internal clean up,          */
225 /*                                            fixed standalone compile,   */
226 /*                                            resulting in version 6.1.11 */
227 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
228 /*                                            fixed parameter/variable    */
229 /*                                            names conflict C++ keyword, */
230 /*                                            resulting in version 6.1.12 */
231 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
232 /*                                            improved VC header check,   */
233 /*                                            resulting in version 6.2.0  */
234 /*                                                                        */
235 /**************************************************************************/
_ux_host_class_video_activate(UX_HOST_CLASS_COMMAND * command)236 UINT  _ux_host_class_video_activate(UX_HOST_CLASS_COMMAND *command)
237 {
238 
239 UX_INTERFACE                            *interface_ptr;
240 UX_HOST_CLASS_VIDEO                     *video;
241 UINT                                    status;
242 UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER  parser;
243 
244 
245     /* The video is always activated by the interface descriptor and not the
246        device descriptor.  */
247     interface_ptr =  (UX_INTERFACE *) command -> ux_host_class_command_container;
248 
249     /* Check the subclass of the new device. If it is a Video Control Interface,
250        we don't need to create an instance of this function. When we get the streaming interface,
251        we will search the video control interface for the device.  */
252     if (interface_ptr -> ux_interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_VIDEO_SUBCLASS_CONTROL)
253         return(UX_SUCCESS);
254 
255     /* Obtain memory for this class instance.  */
256     video =  (UX_HOST_CLASS_VIDEO *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_VIDEO));
257     if (video == UX_NULL)
258         return(UX_MEMORY_INSUFFICIENT);
259 
260     /* Store the class container into this instance.  */
261     video -> ux_host_class_video_class =  command -> ux_host_class_command_class_ptr;
262 
263     /* Store the interface container into the video class instance.  */
264     video -> ux_host_class_video_streaming_interface =  interface_ptr;
265 
266     /* Store the device container into the video class instance.  */
267     video -> ux_host_class_video_device =  interface_ptr -> ux_interface_configuration -> ux_configuration_device;
268 
269     /* This instance of the device must also be stored in the interface container.  */
270     interface_ptr -> ux_interface_class_instance =  (VOID *) video;
271 
272     /* Create this class instance.  */
273     _ux_host_stack_class_instance_create(video -> ux_host_class_video_class, (VOID *) video);
274 
275     /* Configure the video.  */
276     status =  _ux_host_class_video_configure(video);
277 
278     /* Get the video descriptor (all the class specific stuff) and memorize them
279        as we will need these descriptors to change settings.  */
280     if (status == UX_SUCCESS)
281         status =  _ux_host_class_video_descriptor_get(video);
282 
283     /* Use parser to locate streaming terminal, formats and video controls.  */
284     if (status == UX_SUCCESS)
285     {
286         parser.video = video;
287         parser.parsed_flags = 0;
288         video -> ux_host_class_video_control_interface_number = 0xFF;
289         status = _ux_host_class_video_entities_parse(video,
290                         _ux_host_class_video_descriptors_parser, (VOID *)&parser);
291         if (parser.parsed_flags != UX_HOST_CLASS_VIDEO_DESCRIPTORS_PARSER_DONE)
292 
293             /* Some of expected descriptors not found.  */
294             status = UX_HOST_CLASS_VIDEO_WRONG_TYPE;
295     }
296 
297     /* Create the semaphore to protect multiple threads from accessing the same
298        video instance.  */
299     if (status == UX_SUCCESS)
300     {
301         status =  _ux_host_semaphore_create(&video -> ux_host_class_video_semaphore, "ux_video_semaphore", 1);
302         if (status != UX_SUCCESS)
303             status = UX_SEMAPHORE_ERROR;
304     }
305 
306     /* Create the semaphore to protect multiple threads from issuing the control
307        request at the same time.  */
308     if (status == UX_SUCCESS)
309     {
310         status = _ux_host_semaphore_create(&video -> ux_host_class_video_semaphore_control_request, "ux_video_semaphore_control", 1);
311         if (status != UX_SUCCESS)
312             status = UX_SEMAPHORE_ERROR;
313     }
314 
315     if (status == UX_SUCCESS)
316     {
317 
318         /* Mark the video as live now.  */
319         video -> ux_host_class_video_state =  UX_HOST_CLASS_INSTANCE_LIVE;
320 
321         /* If all is fine and the device is mounted, we may need to inform the application
322         if a function has been programmed in the system structure.  */
323         if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
324         {
325 
326             /* Call system change function.  */
327             _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, video -> ux_host_class_video_class, (VOID *) video);
328         }
329 
330         /* If trace is enabled, insert this event into the trace buffer.  */
331         //UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_VIDEO_ACTIVATE, video, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
332 
333         /* If trace is enabled, register this object.  */
334         UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, video, 0, 0, 0)
335 
336         /* Return success.  */
337         return(UX_SUCCESS);
338     }
339 
340     /* There was error, free resources.  */
341 
342     /* The last resource, video -> ux_host_class_video_semaphore_control_request is not created or created error,
343        no need to free.  */
344 
345     /* Destroy the semaphore.  */
346     if (_ux_host_semaphore_created(&video -> ux_host_class_video_semaphore))
347         _ux_host_semaphore_delete(&video -> ux_host_class_video_semaphore);
348 
349     /* Destroy the class instance.  */
350     _ux_host_stack_class_instance_destroy(video -> ux_host_class_video_class, (VOID *) video);
351 
352     /* This instance of the device must also be cleared in the interface container.  */
353     interface_ptr -> ux_interface_class_instance = UX_NULL;
354 
355     /* Free instance memory.  */
356     _ux_utility_memory_free(video);
357 
358     /* Return completion status.  */
359     return(status);
360 }
361 
362