1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 /**************************************************************************/
12 /**************************************************************************/
13 /**                                                                       */
14 /** USBX Component                                                        */
15 /**                                                                       */
16 /**   Device Video 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_video.h"
28 #include "ux_device_stack.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _ux_device_class_video_control_request              PORTABLE C      */
36 /*                                                           6.1.11       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function manages the based sent by the host on the control     */
44 /*    endpoints with a CLASS or VENDOR SPECIFIC type.                     */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    command                               Pointer to class command      */
49 /*                                                                        */
50 /*  OUTPUT                                                                */
51 /*                                                                        */
52 /*    Completion Status                                                   */
53 /*                                                                        */
54 /*  CALLS                                                                 */
55 /*                                                                        */
56 /*    _ux_device_stack_endpoint_stall       Endpoint stall                */
57 /*                                                                        */
58 /*  CALLED BY                                                             */
59 /*                                                                        */
60 /*    Device Video Class                                                  */
61 /*                                                                        */
62 /*  RELEASE HISTORY                                                       */
63 /*                                                                        */
64 /*    DATE              NAME                      DESCRIPTION             */
65 /*                                                                        */
66 /*  04-25-2022     Chaoqiong Xiao           Initial Version 6.1.11        */
67 /*                                                                        */
68 /**************************************************************************/
_ux_device_class_video_control_request(UX_SLAVE_CLASS_COMMAND * command)69 UINT  _ux_device_class_video_control_request(UX_SLAVE_CLASS_COMMAND *command)
70 {
71 
72 UX_SLAVE_TRANSFER             *transfer_request;
73 UX_SLAVE_DEVICE               *device;
74 UX_SLAVE_CLASS                *class_inst;
75 UX_DEVICE_CLASS_VIDEO         *video;
76 UX_DEVICE_CLASS_VIDEO_STREAM  *stream;
77 ULONG                         stream_index;
78 UCHAR                         request_type;
79 UCHAR                         request;
80 UCHAR                         index_low;
81 ULONG                         value_cs;
82 UCHAR                         *buffer;
83 UINT                          status;
84 
85 
86     /* Get the class container.  */
87     class_inst =  command -> ux_slave_class_command_class_ptr;
88 
89     /* Get the video instance from this class container.  */
90     video =  (UX_DEVICE_CLASS_VIDEO *) class_inst -> ux_slave_class_instance;
91 
92     /* Get the pointer to the device.  */
93     device =  &_ux_system_slave -> ux_system_slave_device;
94 
95     /* Get the pointer to the transfer request associated with the control endpoint.  */
96     transfer_request =  &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
97 
98     /* Get bmRequestType, wValue and wIndex low byte.  */
99     request_type = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_REQUEST_TYPE];
100     request = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_REQUEST];
101     value_cs = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_VALUE + 1];
102     index_low = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_INDEX];
103     buffer = transfer_request -> ux_slave_transfer_request_data_pointer;
104 
105     /* Check request target (only target interface is supported now).  */
106     if ((request_type & UX_REQUEST_TARGET) != UX_REQUEST_TARGET_INTERFACE)
107         return(UX_ERROR);
108 
109     /* Check request interface (wIndex low) of control.  */
110     if (index_low == video -> ux_device_class_video_interface -> ux_slave_interface_descriptor.bInterfaceNumber)
111     {
112 
113         /* Check control selector.  */
114         switch(value_cs)
115         {
116         case UX_DEVICE_CLASS_VIDEO_VC_REQUEST_ERROR_CODE_CONTROL:
117 
118             /* Must have at least 1 byte buffer.  */
119             if (transfer_request->ux_slave_transfer_request_requested_length < 1)
120                 return(UX_ERROR);
121 
122             /* GET_CUR.  */
123             if (request == UX_DEVICE_CLASS_VIDEO_GET_CUR)
124             {
125 
126                 /* Fill bRequestErrorCode.  */
127                 *buffer = (UCHAR)video -> ux_device_class_video_error;
128 
129                 /* Send data.  */
130                 status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
131                 return(status);
132             }
133 
134             /* GET_INFO.  */
135             if (request == UX_DEVICE_CLASS_VIDEO_GET_INFO)
136             {
137 
138                 /* Support GET_CUR | GET_INFO.  */
139                 *buffer = UX_DEVICE_CLASS_VIDEO_INFO_GET_REQUEST_SUPPORT;
140 
141                 /* Send data.  */
142                 status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
143                 return(status);
144             }
145 
146             /* Request not expected.  */
147             return(UX_ERROR);
148 
149         default:
150             break;
151         }
152 
153         /* By default it's not handled.  */
154         status = UX_ERROR;
155 
156         /* Invoke callback.  */
157         if (video -> ux_device_class_video_callbacks.ux_device_class_video_request != UX_NULL)
158         {
159 
160             /* Handled by callback.  */
161             status = video -> ux_device_class_video_callbacks.ux_device_class_video_request(video, transfer_request);
162         }
163         return(status);
164     }
165 
166     /* Check request index of stream.  */
167     stream = video -> ux_device_class_video_streams;
168     for (stream_index = 0; stream_index < video -> ux_device_class_video_streams_nb; stream_index ++)
169     {
170 
171         /* No stream.  */
172         if (stream -> ux_device_class_video_stream_interface == UX_NULL)
173             break;
174 
175         /* Check interface number.  */
176         if (index_low == stream -> ux_device_class_video_stream_interface ->
177                                 ux_slave_interface_descriptor.bInterfaceNumber)
178         {
179 
180             /* Check control selector.  */
181             switch(value_cs)
182             {
183             case UX_DEVICE_CLASS_VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
184 
185                 /* Must have at least 1 byte buffer.  */
186                 if (transfer_request->ux_slave_transfer_request_requested_length < 1)
187                     return(UX_ERROR);
188 
189                 /* GET_CUR.  */
190                 if (request == UX_DEVICE_CLASS_VIDEO_GET_CUR)
191                 {
192 
193                     /* Fill bRequestErrorCode.  */
194                     *buffer = (UCHAR)stream -> ux_device_class_video_stream_error;
195 
196                     /* Send data.  */
197                     status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
198                     return(status);
199                 }
200 
201                 /* GET_INFO.  */
202                 if (request == UX_DEVICE_CLASS_VIDEO_GET_INFO)
203                 {
204 
205                     /* Support GET_CUR | GET_INFO.  */
206                     *buffer = UX_DEVICE_CLASS_VIDEO_INFO_GET_REQUEST_SUPPORT;
207 
208                     /* Send data.  */
209                     status = _ux_device_stack_transfer_request(transfer_request, 1, 1);
210                     return(status);
211                 }
212 
213                 /* Request not expected.  */
214                 return(UX_ERROR);
215 
216             default:
217                 break;
218             }
219 
220             /* By default it's not handled.  */
221             status = UX_ERROR;
222 
223             /* Invoke callback.  */
224             if (stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_request != UX_NULL)
225             {
226 
227                 /* Handled by callback.  */
228                 status = stream -> ux_device_class_video_stream_callbacks.ux_device_class_video_stream_request(stream, transfer_request);
229             }
230             return(status);
231         }
232 
233         /* Next stream.  */
234         stream ++;
235     }
236 
237     /* Not handled.  */
238     return(UX_ERROR);
239 }
240