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