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 /** PIMA 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_pima.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_pima_thumb_get PORTABLE C */
37 /* 6.1.10 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function gets a thumb image identified by the object_handle */
45 /* INPUT */
46 /* */
47 /* pima Pointer to pima class */
48 /* pima_session Pointer to pima session */
49 /* object_handle The object handle */
50 /* object Pointer to object info */
51 /* thumb_buffer Buffer to be used */
52 /* thumb_buffer_length Buffer length */
53 /* thumb_actual_length Length read in that */
54 /* command */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* Completion Status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _ux_host_stack_transfer_request Transfer request */
63 /* _ux_host_stack_transfer_request_abort Abort transfer request */
64 /* _ux_host_stack_endpoint_reset Reset endpoint */
65 /* _ux_host_semaphore_get Get protection semaphore */
66 /* _ux_utility_short_put Put 16-bit value */
67 /* _ux_utility_long_put Put 32-bit value */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* USB application */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
78 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
79 /* prefixed UX to MS_TO_TICK, */
80 /* verified memset and memcpy */
81 /* cases, */
82 /* resulting in version 6.1 */
83 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
84 /* refined macros names, */
85 /* resulting in version 6.1.10 */
86 /* */
87 /**************************************************************************/
_ux_host_class_pima_thumb_get(UX_HOST_CLASS_PIMA * pima,UX_HOST_CLASS_PIMA_SESSION * pima_session,ULONG object_handle,UX_HOST_CLASS_PIMA_OBJECT * object,UCHAR * thumb_buffer,ULONG thumb_buffer_length,ULONG * thumb_actual_length)88 UINT _ux_host_class_pima_thumb_get(UX_HOST_CLASS_PIMA *pima,
89 UX_HOST_CLASS_PIMA_SESSION *pima_session,
90 ULONG object_handle, UX_HOST_CLASS_PIMA_OBJECT *object,
91 UCHAR *thumb_buffer, ULONG thumb_buffer_length,
92 ULONG *thumb_actual_length)
93 {
94
95 UX_HOST_CLASS_PIMA_COMMAND command;
96 UX_TRANSFER *transfer_request;
97 UCHAR *ptp_payload;
98 ULONG requested_length;
99 UINT status;
100
101 /* If trace is enabled, insert this event into the trace buffer. */
102 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PIMA_THUMB_GET, pima, object_handle, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
103
104 /* Check if this session is valid or not. */
105 if (pima_session -> ux_host_class_pima_session_magic != UX_HOST_CLASS_PIMA_MAGIC_NUMBER)
106 return (UX_HOST_CLASS_PIMA_RC_SESSION_NOT_OPEN);
107
108 /* Check if this session is opened or not. */
109 if (pima_session -> ux_host_class_pima_session_state != UX_HOST_CLASS_PIMA_SESSION_STATE_OPENED)
110 return (UX_HOST_CLASS_PIMA_RC_SESSION_NOT_OPEN);
111
112 /* Check if the object is already opened. */
113 if (object -> ux_host_class_pima_object_state != UX_HOST_CLASS_PIMA_OBJECT_STATE_OPENED)
114 return (UX_HOST_CLASS_PIMA_RC_OBJECT_NOT_OPENED);
115
116 /* Check the transfer status. If there was an error or transfer is completed, refuse transfer. */
117 if ((object -> ux_host_class_pima_object_transfer_status == UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_COMPLETED) ||
118 (object -> ux_host_class_pima_object_transfer_status == UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_ABORTED))
119 return (UX_HOST_CLASS_PIMA_RC_ACCESS_DENIED);
120
121
122 /* Reset the actual length. */
123 *thumb_actual_length = 0;
124
125 /* This variable will remain untouched if the offset is not 0 and the requested length is 0. */
126 status = UX_SUCCESS;
127
128 /* Check if the offset to be read is at 0, if so, prepare the first read command. */
129 if (object -> ux_host_class_pima_object_offset == 0)
130 {
131
132 /* Set the object transfer status to active. */
133 object -> ux_host_class_pima_object_transfer_status = UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_ACTIVE;
134
135 /* Issue command to get the object info. 1 parameter. */
136 command.ux_host_class_pima_command_nb_parameters = 1;
137
138 /* Parameter 1 is the Object Handle. */
139 command.ux_host_class_pima_command_parameter_1 = object_handle;
140
141 /* Then set the command to GET_OBJECT. */
142 command.ux_host_class_pima_command_operation_code = UX_HOST_CLASS_PIMA_OC_GET_THUMB;
143
144 /* We use the Bulk Out pipe for sending data out.. */
145 transfer_request = &pima -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request;
146
147 /* Get the pointer to the ptp payload. */
148 ptp_payload = pima -> ux_host_class_pima_container ;
149
150 /* Calculate the requested length for this payload. */
151 requested_length = UX_HOST_CLASS_PIMA_COMMAND_HEADER_SIZE + ((ULONG)sizeof(ULONG) * command.ux_host_class_pima_command_nb_parameters);
152
153 /* Fill the command container. First the length of the total header and payload. */
154 _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_LENGTH, requested_length);
155
156 /* Then the type of container : a command block here. */
157 _ux_utility_short_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_TYPE, UX_HOST_CLASS_PIMA_CT_COMMAND_BLOCK);
158
159 /* Now the command code to send. */
160 _ux_utility_short_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_CODE, (USHORT)command.ux_host_class_pima_command_operation_code);
161
162 /* Put the transaction ID. */
163 _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_TRANSACTION_ID,
164 pima -> ux_host_class_pima_transaction_id++);
165
166 /* Then fill in the parameters. */
167 _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_PARAMETER_1,
168 command.ux_host_class_pima_command_parameter_1);
169
170 /* Initialize the transfer_request. */
171 transfer_request -> ux_transfer_request_data_pointer = ptp_payload;
172 transfer_request -> ux_transfer_request_requested_length = requested_length;
173
174 /* Send request to HCD layer. */
175 status = _ux_host_stack_transfer_request(transfer_request);
176
177 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
178 if (status == UX_SUCCESS)
179 {
180
181 /* Wait for the completion of the transfer request. */
182 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PIMA_CLASS_TRANSFER_TIMEOUT));
183
184 /* If the semaphore did not succeed we probably have a time out. */
185 if (status != UX_SUCCESS)
186 {
187
188 /* All transfers pending need to abort. There may have been a partial transfer. */
189 _ux_host_stack_transfer_request_abort(transfer_request);
190
191 /* The endpoint was halted by a transfer error and needs to be reset. */
192 _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_in_endpoint);
193
194 /* The endpoint was halted by a transfer error and needs to be reset. */
195 _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_out_endpoint);
196
197 /* Set the thumb transfer status to aborted. */
198 object -> ux_host_class_pima_object_transfer_status = UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_ABORTED;
199
200 /* There was an error, return to the caller. */
201 return(status);
202 }
203 }
204 else
205 {
206
207 /* There was a non transfer error, no partial transfer to be checked */
208 return(status);
209 }
210
211 /* Check for completion of transfer. If the transfer is partial, return to caller.
212 Partial transfer is not OK. */
213 if (requested_length == transfer_request -> ux_transfer_request_actual_length)
214 {
215
216 /* Obtain the first packet. This packet contains the header and some data.
217 We use the Bulk In pipe for receiving data .. */
218 transfer_request = &pima -> ux_host_class_pima_bulk_in_endpoint -> ux_endpoint_transfer_request;
219
220 /* Get the pointer to the ptp payload. */
221 ptp_payload = pima -> ux_host_class_pima_container ;
222
223 /* Calculate the requested length for this payload. */
224 requested_length = UX_HOST_CLASS_PIMA_CONTAINER_SIZE;
225
226 /* Initialize the transfer_request. */
227 transfer_request -> ux_transfer_request_data_pointer = ptp_payload;
228 transfer_request -> ux_transfer_request_requested_length = requested_length;
229
230 /* Send request to HCD layer. */
231 status = _ux_host_stack_transfer_request(transfer_request);
232
233 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
234 if (status == UX_SUCCESS)
235 {
236
237 /* Wait for the completion of the transfer request. */
238 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PIMA_CLASS_TRANSFER_TIMEOUT));
239
240 /* If the semaphore did not succeed we probably have a time out. */
241 if (status != UX_SUCCESS)
242 {
243
244 /* All transfers pending need to abort. There may have been a partial transfer. */
245 _ux_host_stack_transfer_request_abort(transfer_request);
246
247 /* The endpoint was halted by a transfer error and needs to be reset. */
248 _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_in_endpoint);
249
250 /* The endpoint was halted by a transfer error and needs to be reset. */
251 _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_out_endpoint);
252
253 /* Set the thumb transfer status to aborted. */
254 object -> ux_host_class_pima_object_transfer_status = UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_ABORTED;
255
256 /* There was an error, return to the caller. */
257 return(status);
258 }
259 }
260 else
261 {
262
263 /* There was a non transfer error, no partial transfer to be checked */
264 return(status);
265 }
266
267 /* Ensure transfer length is greater than the size of the header. */
268 if (transfer_request -> ux_transfer_request_actual_length <= UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE)
269
270 /* We have a malformed packet. Return error. */
271 return(UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR);
272
273 /* Ensure there's enough room in the application's buffer. */
274 if (thumb_buffer_length < transfer_request -> ux_transfer_request_actual_length - UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE)
275
276 /* Not enough room. Return error. */
277 return(UX_MEMORY_INSUFFICIENT);
278
279 /* We need to skip the header. Copying the necessary partial memory only. */
280 _ux_utility_memory_copy(thumb_buffer, ptp_payload + UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE,
281 transfer_request -> ux_transfer_request_actual_length - UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE); /* Use case of memcpy is verified. */
282
283 /* Update the actual length. */
284 *thumb_actual_length = transfer_request -> ux_transfer_request_actual_length - UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE;
285
286 /* And the offset. */
287 object -> ux_host_class_pima_object_offset += transfer_request -> ux_transfer_request_actual_length - UX_HOST_CLASS_PIMA_DATA_HEADER_SIZE;
288
289 }
290 else
291
292 /* We got a premature error. */
293 return(UX_HOST_CLASS_PIMA_RC_INCOMPLETE_TRANSFER);
294 }
295
296 else
297 {
298
299 /* We use the Bulk In pipe for receiving data .. */
300 transfer_request = &pima -> ux_host_class_pima_bulk_in_endpoint -> ux_endpoint_transfer_request;
301
302 /* We read a complete block. */
303 while(thumb_buffer_length != 0)
304 {
305
306 /* It may take several transactions. */
307 if (thumb_buffer_length > UX_HOST_CLASS_PIMA_MAX_PAYLOAD)
308
309 /* Set the requested length to the payload maximum. */
310 requested_length = UX_HOST_CLASS_PIMA_MAX_PAYLOAD;
311
312 else
313
314 /* We can use the user supplied length to complete this request. */
315 requested_length = thumb_buffer_length;
316
317 /* Initialize the transfer_request. */
318 transfer_request -> ux_transfer_request_data_pointer = thumb_buffer;
319 transfer_request -> ux_transfer_request_requested_length = requested_length;
320
321 /* Send request to HCD layer. */
322 status = _ux_host_stack_transfer_request(transfer_request);
323
324 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
325 if (status == UX_SUCCESS)
326 {
327
328 /* Wait for the completion of the transfer request. */
329 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PIMA_CLASS_TRANSFER_TIMEOUT));
330
331 /* If the semaphore did not succeed we probably have a time out. */
332 if (status != UX_SUCCESS)
333 {
334
335 /* All transfers pending need to abort. There may have been a partial transfer. */
336 _ux_host_stack_transfer_request_abort(transfer_request);
337
338 /* The endpoint was halted by a transfer error and needs to be reset. */
339 _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_in_endpoint);
340
341 /* The endpoint was halted by a transfer error and needs to be reset. */
342 _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_out_endpoint);
343
344 /* Set the thumb transfer status to aborted. */
345 object -> ux_host_class_pima_object_transfer_status = UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_ABORTED;
346
347 /* There was an error, return to the caller. */
348 return(status);
349 }
350 }
351 else
352 {
353
354 /* There was a non transfer error, no partial transfer to be checked */
355 return(status);
356 }
357
358 /* Update the object length expected by the user with what we actually received. */
359 thumb_buffer_length -= transfer_request -> ux_transfer_request_actual_length;
360
361 /* Update the actual length. */
362 *thumb_actual_length += transfer_request -> ux_transfer_request_actual_length;
363
364 /* And the offset. */
365 object -> ux_host_class_pima_object_offset += transfer_request -> ux_transfer_request_actual_length;
366
367 /* Check to see if we are at the end of the object. */
368 if (object -> ux_host_class_pima_object_offset == object -> ux_host_class_pima_object_thumb_compressed_size)
369
370 /* The transfer for this transaction is completed. */
371 object -> ux_host_class_pima_object_transfer_status = UX_HOST_CLASS_PIMA_OBJECT_TRANSFER_STATUS_COMPLETED;
372
373 }
374
375 }
376 /* Return completion status. */
377 return(status);
378 }
379
380 /**************************************************************************/
381 /* */
382 /* FUNCTION RELEASE */
383 /* */
384 /* _uxe_host_class_pima_thumb_get PORTABLE C */
385 /* 6.3.0 */
386 /* AUTHOR */
387 /* */
388 /* Yajun Xia, Microsoft Corporation */
389 /* */
390 /* DESCRIPTION */
391 /* */
392 /* This function checks errors in pima object thumb function call. */
393 /* */
394 /* INPUT */
395 /* */
396 /* pima Pointer to pima class */
397 /* pima_session Pointer to pima session */
398 /* object_handle The object handle */
399 /* object Pointer to object info */
400 /* thumb_buffer Buffer to be used */
401 /* thumb_buffer_length Buffer length */
402 /* thumb_actual_length Length read in that */
403 /* command */
404 /* */
405 /* OUTPUT */
406 /* */
407 /* Completion Status */
408 /* */
409 /* CALLS */
410 /* */
411 /* _ue_host_class_pima_thumb_get Get pima thumb */
412 /* */
413 /* CALLED BY */
414 /* */
415 /* USB application */
416 /* */
417 /* RELEASE HISTORY */
418 /* */
419 /* DATE NAME DESCRIPTION */
420 /* */
421 /* 10-31-2023 Yajun xia Initial Version 6.3.0 */
422 /* */
423 /**************************************************************************/
_uxe_host_class_pima_thumb_get(UX_HOST_CLASS_PIMA * pima,UX_HOST_CLASS_PIMA_SESSION * pima_session,ULONG object_handle,UX_HOST_CLASS_PIMA_OBJECT * object,UCHAR * thumb_buffer,ULONG thumb_buffer_length,ULONG * thumb_actual_length)424 UINT _uxe_host_class_pima_thumb_get(UX_HOST_CLASS_PIMA *pima,
425 UX_HOST_CLASS_PIMA_SESSION *pima_session,
426 ULONG object_handle, UX_HOST_CLASS_PIMA_OBJECT *object,
427 UCHAR *thumb_buffer, ULONG thumb_buffer_length,
428 ULONG *thumb_actual_length)
429 {
430
431 /* Sanity checks. */
432 if ((pima == UX_NULL) || (pima_session == UX_NULL) || (object == UX_NULL) || (thumb_buffer == UX_NULL) || (thumb_actual_length == UX_NULL))
433 return(UX_INVALID_PARAMETER);
434
435 /* Call the actual function. */
436 return(_ux_host_class_pima_thumb_get(pima, pima_session, object_handle, object, thumb_buffer, thumb_buffer_length, thumb_actual_length));
437 }