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 /** */
15 /** USBX Component */
16 /** */
17 /** Video Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_video.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_video_transfer_buffers_add PORTABLE C */
37 /* 6.3.0 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function adds buffers for video transfer requests. */
45 /* */
46 /* Usually it's the very first step to start a video stream on a high */
47 /* bandwidth isochronous endpoint. Since adding new buffer while */
48 /* the prepared buffers in progress helps to improve performance. */
49 /* */
50 /* Note the maximum number of transfers could be buffered is */
51 /* UX_HOST_CLASS_VIDEO_TRANSFER_REQUEST_COUNT - 1. */
52 /* */
53 /* Note check ux_host_class_video_max_payload_get to see minimum */
54 /* recommended buffer size. */
55 /* */
56 /* INPUT */
57 /* */
58 /* video Pointer to video class */
59 /* buffers Pointer to data buffer */
60 /* pointers array */
61 /* num_buffers Number of data buffers */
62 /* */
63 /* OUTPUT */
64 /* */
65 /* Completion Status */
66 /* */
67 /* CALLS */
68 /* */
69 /* _ux_host_stack_class_instance_verify Verify instance is valid */
70 /* _ux_host_stack_transfer_request Process transfer request */
71 /* _ux_host_semaphore_get Get semaphore */
72 /* _ux_host_semaphore_put Release semaphore */
73 /* _ux_system_error_handler Log system error */
74 /* */
75 /* CALLED BY */
76 /* */
77 /* Application */
78 /* */
79 /* RELEASE HISTORY */
80 /* */
81 /* DATE NAME DESCRIPTION */
82 /* */
83 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
84 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
85 /* resulting in version 6.1 */
86 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
87 /* use pre-calculated value */
88 /* instead of wMaxPacketSize, */
89 /* resulting in version 6.1.9 */
90 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
91 /* refined macros names, */
92 /* resulting in version 6.1.10 */
93 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
94 /* fixed standalone compile, */
95 /* resulting in version 6.1.11 */
96 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
97 /* set pending on endpoint, */
98 /* resulting in version 6.1.12 */
99 /* 10-31-2023 Yajun xia Modified comment(s), */
100 /* resulting in version 6.3.0 */
101 /* */
102 /**************************************************************************/
_ux_host_class_video_transfer_buffers_add(UX_HOST_CLASS_VIDEO * video,UCHAR ** buffers,ULONG num_buffers)103 UINT _ux_host_class_video_transfer_buffers_add(UX_HOST_CLASS_VIDEO *video, UCHAR** buffers, ULONG num_buffers)
104 {
105
106 UINT status;
107 UX_TRANSFER *transfer_request;
108 UX_TRANSFER *previous_transfer;
109 UX_ENDPOINT *endpoint;
110 ULONG transfer_index;
111 ULONG packet_size;
112 UINT i;
113
114
115 /* Ensure the instance is valid. */
116 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_video_name, (VOID *) video) != UX_SUCCESS)
117 {
118
119 /* Error trap. */
120 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
121
122 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
123 }
124
125 /* Protect thread reentry to this instance. */
126 status = _ux_host_semaphore_get(&video -> ux_host_class_video_semaphore, UX_WAIT_FOREVER);
127 if (status != UX_SUCCESS)
128 return(status);
129
130 /* Get endpoint. */
131 endpoint = video -> ux_host_class_video_isochronous_endpoint;
132
133 /* Ensure we have a selected interface that allows isoch transmission. */
134 if ((endpoint == UX_NULL) ||
135 (endpoint -> ux_endpoint_descriptor.wMaxPacketSize == 0))
136 {
137
138 /* Unprotect thread reentry to this instance. */
139 _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
140
141 /* Error trap. */
142 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_VIDEO_WRONG_INTERFACE);
143
144 /* Return error status. */
145 return(UX_HOST_CLASS_VIDEO_WRONG_INTERFACE);
146 }
147
148 /* Check if there is enough requests available. */
149 if (video -> ux_host_class_video_transfer_request_start_index >=
150 video -> ux_host_class_video_transfer_request_end_index)
151 {
152
153 if (video -> ux_host_class_video_transfer_request_start_index + num_buffers >=
154 video -> ux_host_class_video_transfer_request_end_index + UX_HOST_CLASS_VIDEO_TRANSFER_REQUEST_COUNT)
155 status = (UX_MEMORY_ARRAY_FULL);
156 }
157 else
158 {
159 if (video -> ux_host_class_video_transfer_request_start_index + num_buffers >=
160 video -> ux_host_class_video_transfer_request_end_index)
161 status = (UX_MEMORY_ARRAY_FULL);
162 }
163
164 /* Check error. */
165 if (status != UX_SUCCESS)
166 {
167
168 /* Unprotect thread reentry to this instance. */
169 _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
170
171 /* Return error status. */
172 return(status);
173 }
174
175 /* Calculate packet size. */
176 packet_size = video -> ux_host_class_video_current_max_payload_size;
177
178 /* Add buffers one by one. */
179 for (i = 0,
180 transfer_index = video -> ux_host_class_video_transfer_request_start_index,
181 previous_transfer = UX_NULL;
182 i < num_buffers; i ++)
183 {
184
185 transfer_request = &video->ux_host_class_video_transfer_requests[transfer_index];
186
187 /* Select the direction. We do this by taking the endpoint direction. */
188 transfer_request -> ux_transfer_request_type = endpoint ->
189 ux_endpoint_descriptor.bEndpointAddress & UX_REQUEST_DIRECTION;
190
191 /* Fill the transfer request with all the required fields. */
192 transfer_request -> ux_transfer_request_endpoint = endpoint;
193 transfer_request -> ux_transfer_request_data_pointer = buffers[i];
194 transfer_request -> ux_transfer_request_requested_length = packet_size;
195 transfer_request -> ux_transfer_request_completion_function = _ux_host_class_video_transfer_request_callback;
196 transfer_request -> ux_transfer_request_class_instance = video;
197
198 /* Confirm the transfer request is single one. */
199 transfer_request -> ux_transfer_request_next_transfer_request = UX_NULL;
200
201 /* Link to transfer request tail. */
202 if (previous_transfer)
203 previous_transfer -> ux_transfer_request_next_transfer_request = transfer_request;
204
205 /* Save as previous request. */
206 previous_transfer = transfer_request;
207
208 /* Move to next transfer request. */
209 transfer_index ++;
210 if (transfer_index >= UX_HOST_CLASS_VIDEO_TRANSFER_REQUEST_COUNT)
211 transfer_index = 0;
212 }
213
214 /* Get request list head. */
215 transfer_request = &video -> ux_host_class_video_transfer_requests[video->ux_host_class_video_transfer_request_start_index];
216
217 /* Move request index. */
218 video -> ux_host_class_video_transfer_request_start_index = transfer_index;
219
220 /* Set endpoint to pending state, for callback and abort to check. */
221 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING;
222
223 /* Transfer the transfer request (list). */
224 status = _ux_host_stack_transfer_request(transfer_request);
225
226 /* Unprotect thread reentry to this instance. */
227 _ux_host_semaphore_put(&video -> ux_host_class_video_semaphore);
228
229 /* Return completion status. */
230 return(status);
231 }
232
233 /**************************************************************************/
234 /* */
235 /* FUNCTION RELEASE */
236 /* */
237 /* _uxe_host_class_video_transfer_buffers_add PORTABLE C */
238 /* 6.3.0 */
239 /* AUTHOR */
240 /* */
241 /* Yajun Xia, Microsoft Corporation */
242 /* */
243 /* DESCRIPTION */
244 /* */
245 /* This function checks errors in video transfer buffers add function */
246 /* call. */
247 /* */
248 /* INPUT */
249 /* */
250 /* video Pointer to video class */
251 /* buffers Pointer to data buffer */
252 /* pointers array */
253 /* num_buffers Number of data buffers */
254 /* */
255 /* OUTPUT */
256 /* */
257 /* Completion Status */
258 /* */
259 /* CALLS */
260 /* */
261 /* _ux_host_class_video_transfer_buffers_add */
262 /* video transfer buffers add */
263 /* */
264 /* CALLED BY */
265 /* */
266 /* Application */
267 /* */
268 /* RELEASE HISTORY */
269 /* */
270 /* DATE NAME DESCRIPTION */
271 /* */
272 /* 10-31-2023 Yajun xia Initial Version 6.3.0 */
273 /* */
274 /**************************************************************************/
_uxe_host_class_video_transfer_buffers_add(UX_HOST_CLASS_VIDEO * video,UCHAR ** buffers,ULONG num_buffers)275 UINT _uxe_host_class_video_transfer_buffers_add(UX_HOST_CLASS_VIDEO *video, UCHAR** buffers, ULONG num_buffers)
276 {
277
278 /* Sanity checks. */
279 if ((video == UX_NULL) || (buffers == UX_NULL) || (num_buffers == 0))
280 return(UX_INVALID_PARAMETER);
281
282 /* Call the actual video transfer buffers add function. */
283 return(_ux_host_class_video_transfer_buffers_add(video, buffers, num_buffers));
284 }
285