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