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