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_command                         PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function will send a command to the PIMA device.               */
45 /*    It will perform a data phase if necessary and the status phase.     */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    pima                                  Pointer to pima class         */
50 /*    command                               pointer to command container  */
51 /*    direction                             either IN or OUT              */
52 /*    data_buffer                           buffer to be sent or received */
53 /*    data_length                           length of the buffer to send  */
54 /*                                          or receive                    */
55 /*    max_payload_length                    maximum payload length        */
56 /*                                                                        */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    Completion Status                                                   */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _ux_host_stack_transfer_request       Process transfer request      */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    Application                                                         */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
75 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            prefixed UX to MS_TO_TICK,  */
77 /*                                            resulting in version 6.1    */
78 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            refined macros names,       */
80 /*                                            resulting in version 6.1.10 */
81 /*  10-31-2023     Yajun xia                Modified comment(s),          */
82 /*                                            resulting in version 6.3.0  */
83 /*                                                                        */
84 /**************************************************************************/
_ux_host_class_pima_command(UX_HOST_CLASS_PIMA * pima,UX_HOST_CLASS_PIMA_COMMAND * command,ULONG direction,UCHAR * data_buffer,ULONG data_length,ULONG max_payload_length)85 UINT  _ux_host_class_pima_command(UX_HOST_CLASS_PIMA *pima, UX_HOST_CLASS_PIMA_COMMAND *command,
86                                     ULONG direction, UCHAR *data_buffer, ULONG data_length,
87                                     ULONG max_payload_length)
88 {
89 
90 UX_TRANSFER     *transfer_request;
91 UCHAR             *ptp_payload;
92 ULONG            requested_length;
93 UINT            status;
94 
95     /* We use the Bulk Out pipe for sending data out..  */
96     transfer_request =  &pima -> ux_host_class_pima_bulk_out_endpoint -> ux_endpoint_transfer_request;
97 
98     /* Get the pointer to the ptp payload.  */
99     ptp_payload =  pima -> ux_host_class_pima_container ;
100 
101     /* Calculate the requested length for this payload.  */
102     requested_length =  UX_HOST_CLASS_PIMA_COMMAND_HEADER_SIZE + ((ULONG)sizeof(ULONG) * command -> ux_host_class_pima_command_nb_parameters);
103 
104     /* Fill the command container. First the length of the total header and payload.  */
105     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_LENGTH, requested_length);
106 
107     /* Then the type of container : a command block here.  */
108     _ux_utility_short_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_TYPE, UX_HOST_CLASS_PIMA_CT_COMMAND_BLOCK);
109 
110     /* Now the command code to send.  */
111     _ux_utility_short_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_CODE, (USHORT)command -> ux_host_class_pima_command_operation_code);
112 
113     /* Save the operation code.  */
114     pima -> ux_host_class_pima_operation_code =  command -> ux_host_class_pima_command_operation_code;
115 
116     /* Put the transaction ID.  */
117     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_TRANSACTION_ID,
118                         pima -> ux_host_class_pima_transaction_id++);
119 
120     /* Then fill in all the parameters. To make it quick we fill the 5 parameters, regardless
121        of the number contained in the command. But when the payload is transmitted, only the
122        relevant data is sent over the Bulk Out pipe.  */
123     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_PARAMETER_1,
124                         command -> ux_host_class_pima_command_parameter_1);
125     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_PARAMETER_2,
126                         command -> ux_host_class_pima_command_parameter_2);
127     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_PARAMETER_3,
128                         command -> ux_host_class_pima_command_parameter_3);
129     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_PARAMETER_4,
130                         command -> ux_host_class_pima_command_parameter_4);
131     _ux_utility_long_put(ptp_payload + UX_HOST_CLASS_PIMA_COMMAND_HEADER_PARAMETER_5,
132                         command -> ux_host_class_pima_command_parameter_5);
133 
134     /* Initialize the transfer_request.  */
135     transfer_request -> ux_transfer_request_data_pointer =  ptp_payload;
136     transfer_request -> ux_transfer_request_requested_length =  requested_length;
137 
138     /* Send request to HCD layer.  */
139     status =  _ux_host_stack_transfer_request(transfer_request);
140 
141     /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
142     if (status == UX_SUCCESS)
143     {
144 
145         /* Wait for the completion of the transfer request.  */
146         status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PIMA_CLASS_TRANSFER_TIMEOUT));
147 
148         /* If the semaphore did not succeed we probably have a time out.  */
149         if (status != UX_SUCCESS)
150         {
151 
152             /* All transfers pending need to abort. There may have been a partial transfer.  */
153             _ux_host_stack_transfer_request_abort(transfer_request);
154 
155             /* The endpoint was halted by a transfer error and needs to be reset.  */
156             _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_in_endpoint);
157 
158             /* The endpoint was halted by a transfer error  and needs to be reset.  */
159             _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_out_endpoint);
160 
161             /* Set the completion code.  */
162             transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
163 
164             /* Error trap. */
165             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
166 
167             /* If trace is enabled, insert this event into the trace buffer.  */
168             UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
169 
170             /* There was an error, return to the caller.  */
171             return(UX_TRANSFER_TIMEOUT);
172         }
173     }
174     else
175     {
176 
177         /* There was a non transfer error, no partial transfer to be checked */
178         return(status);
179     }
180 
181     /* Check for completion of transfer. If the transfer is partial, return to caller.
182        Partial transfer is not OK. */
183     if (requested_length == transfer_request -> ux_transfer_request_actual_length)
184     {
185 
186         /* The command was sent successfully. Now examine the direction and check
187            if we need a data phase. If so which direction.  */
188 
189         switch (direction)
190         {
191 
192             /* No data phase, proceed to response directly. */
193             case     UX_HOST_CLASS_PIMA_DATA_PHASE_NONE    :
194 
195                 /* No error here.  */
196                 status = UX_SUCCESS;
197                 break;
198 
199             /* We need to transfer data IN.  */
200             case    UX_HOST_CLASS_PIMA_DATA_PHASE_IN    :
201                 status = _ux_host_class_pima_read(pima, data_buffer, data_length, max_payload_length);
202                 break;
203 
204             /* We need to transfer data OUT.  */
205             case    UX_HOST_CLASS_PIMA_DATA_PHASE_OUT    :
206                 status = _ux_host_class_pima_write(pima, data_buffer, data_length, command -> ux_host_class_pima_command_operation_code,
207                                                     max_payload_length);
208                 break;
209 
210             default                                     :
211                 return(UX_ERROR);
212 
213         }
214 
215         /* Analyze the status. If no errors during the data phase proceed to response code.  */
216         if (status == UX_SUCCESS)
217         {
218 
219             /* We use the Bulk In pipe for receiving the response payload ..  */
220             transfer_request =  &pima -> ux_host_class_pima_bulk_in_endpoint -> ux_endpoint_transfer_request;
221 
222             /* Get the pointer to the ptp payload.  */
223             ptp_payload =  pima -> ux_host_class_pima_container ;
224 
225             /* Calculate the requested length for this payload.  */
226             requested_length =  UX_HOST_CLASS_PIMA_RESPONSE_HEADER_SIZE;
227 
228             /* Initialize the transfer_request.  */
229             transfer_request -> ux_transfer_request_data_pointer =  ptp_payload;
230             transfer_request -> ux_transfer_request_requested_length =  requested_length;
231 
232             /* Send request to HCD layer.  */
233             status =  _ux_host_stack_transfer_request(transfer_request);
234 
235             /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
236             if (status == UX_SUCCESS)
237             {
238 
239                 /* Wait for the completion of the transfer request.  */
240                 status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PIMA_CLASS_TRANSFER_TIMEOUT));
241 
242                 /* If the semaphore did not succeed we probably have a time out.  */
243                 if (status != UX_SUCCESS)
244                 {
245 
246                     /* All transfers pending need to abort. There may have been a partial transfer.  */
247                     _ux_host_stack_transfer_request_abort(transfer_request);
248 
249                     /* The endpoint was halted by a transfer error and needs to be reset.  */
250                     _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_in_endpoint);
251 
252                     /* The endpoint was halted by a transfer error  and needs to be reset.  */
253                     _ux_host_stack_endpoint_reset(pima -> ux_host_class_pima_bulk_out_endpoint);
254 
255                     /* Set the completion code.  */
256                     transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
257 
258                     /* Error trap. */
259                     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
260 
261                     /* If trace is enabled, insert this event into the trace buffer.  */
262                     UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
263 
264                     /* There was an error, return to the caller.  */
265                     return(UX_TRANSFER_TIMEOUT);
266                 }
267             }
268             else
269             {
270 
271                 /* There was a non transfer error, no partial transfer to be checked */
272                 return(status);
273             }
274 
275             /* Check to ensure this is a Response packet.  */
276             if (_ux_utility_short_get(ptp_payload + UX_HOST_CLASS_PIMA_RESPONSE_HEADER_TYPE) !=
277                                         UX_HOST_CLASS_PIMA_CT_RESPONSE_BLOCK)
278 
279                 /* We have a wrong packet.  */
280                 return(UX_ERROR);
281 
282             /* Then get all the response parameters.  */
283             command -> ux_host_class_pima_command_parameter_1 =  _ux_utility_long_get(ptp_payload +
284                                                                  UX_HOST_CLASS_PIMA_RESPONSE_HEADER_PARAMETER_1);
285             command -> ux_host_class_pima_command_parameter_2 =  _ux_utility_long_get(ptp_payload +
286                                                                  UX_HOST_CLASS_PIMA_RESPONSE_HEADER_PARAMETER_2);
287             command -> ux_host_class_pima_command_parameter_3 =  _ux_utility_long_get(ptp_payload +
288                                                                  UX_HOST_CLASS_PIMA_RESPONSE_HEADER_PARAMETER_3);
289             command -> ux_host_class_pima_command_parameter_4 =  _ux_utility_long_get(ptp_payload +
290                                                                  UX_HOST_CLASS_PIMA_RESPONSE_HEADER_PARAMETER_4);
291             command -> ux_host_class_pima_command_parameter_5 =  _ux_utility_long_get(ptp_payload +
292                                                                  UX_HOST_CLASS_PIMA_RESPONSE_HEADER_PARAMETER_5);
293 
294             /* We are done with the command.  */
295             return(UX_SUCCESS);
296         }
297         /* Return the error.  */
298         return(status);
299     }
300     else
301         /* Truncated command. */
302         return(UX_TRANSFER_ERROR);
303 
304 }
305 
306