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