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 /** Device Pima Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define UX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "ux_api.h"
28 #include "ux_device_class_pima.h"
29 #include "ux_device_stack.h"
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_pima_object_data_get PORTABLE C */
36 /* 6.1.10 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function returns the object data to the host. */
44 /* */
45 /* INPUT */
46 /* */
47 /* pima Pointer to pima class */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* Completion Status */
52 /* */
53 /* CALLS */
54 /* */
55 /* _ux_device_stack_transfer_request Transfer request */
56 /* _ux_utility_long_put Put 32-bit value */
57 /* _ux_utility_short_put Put 32-bit value */
58 /* _ux_device_class_pima_response_send Send PIMA response */
59 /* _ux_device_stack_endpoint_stall Stall endpoint */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* Device Storage Class */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
70 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
71 /* resulting in version 6.1 */
72 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
73 /* updated status handling, */
74 /* improved sanity checks, */
75 /* improved cancel flow, */
76 /* resulting in version 6.1.10 */
77 /* */
78 /**************************************************************************/
_ux_device_class_pima_object_data_get(UX_SLAVE_CLASS_PIMA * pima,ULONG object_handle)79 UINT _ux_device_class_pima_object_data_get(UX_SLAVE_CLASS_PIMA *pima, ULONG object_handle)
80 {
81
82 UINT status;
83 UX_SLAVE_TRANSFER *transfer_request;
84 UX_SLAVE_CLASS_PIMA_OBJECT *object;
85 UCHAR *object_data;
86 ULONG object_offset;
87 ULONG object_length;
88 ULONG total_length;
89 ULONG object_length_demanded;
90 ULONG object_length_received;
91
92 /* If trace is enabled, insert this event into the trace buffer. */
93 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PIMA_OBJECT_DATA_GET, pima, object_handle, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
94
95 /* Obtain the object info from the application. */
96 status = pima -> ux_device_class_pima_object_info_get(pima, object_handle, &object);
97
98 /* Check for error. */
99 if (status == UX_SUCCESS)
100 {
101
102 /* Data phase (Bulk IN). */
103 pima -> ux_device_class_pima_state = UX_DEVICE_CLASS_PIMA_PHASE_DATA_IN;
104
105 /* Set the object length. */
106 object_length = object -> ux_device_class_pima_object_compressed_size;
107
108 /* Set the total length to be sent. */
109 total_length = object_length + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE;
110
111 /* Reset the offset. */
112 object_offset = 0;
113
114 /* Obtain the pointer to the transfer request of the bulk in endpoint. */
115 transfer_request = &pima -> ux_device_class_pima_bulk_in_endpoint -> ux_slave_endpoint_transfer_request;
116
117 /* Obtain memory for this object info. Use the transfer request pre-allocated memory. */
118 object_data = transfer_request -> ux_slave_transfer_request_data_pointer;
119
120 /* Fill in the total length to be sent (header + payload. */
121 _ux_utility_long_put(object_data + UX_DEVICE_CLASS_PIMA_DATA_HEADER_LENGTH,
122 total_length);
123
124 /* Fill in the data container type. */
125 _ux_utility_short_put(object_data + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TYPE,
126 UX_DEVICE_CLASS_PIMA_CT_DATA_BLOCK);
127
128 /* Fill in the data code. */
129 _ux_utility_short_put(object_data + UX_DEVICE_CLASS_PIMA_DATA_HEADER_CODE,
130 UX_DEVICE_CLASS_PIMA_OC_GET_OBJECT);
131
132 /* Fill in the Transaction ID. */
133 _ux_utility_long_put(object_data + UX_DEVICE_CLASS_PIMA_DATA_HEADER_TRANSACTION_ID,
134 pima -> ux_device_class_pima_transaction_id);
135
136 /* Assuming the host will ask for the entire object. */
137 while (object_length != 0)
138 {
139
140 /* If this is the first packet, we have to take into account the
141 header. */
142 if (object_offset == 0)
143 {
144
145 /* Calculate the maximum length for the first packet. */
146 object_length_demanded = UX_DEVICE_CLASS_PIMA_TRANSFER_BUFFER_LENGTH -
147 UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE;
148
149 /* Can we get that much from the application ? */
150 if (object_length_demanded > object_length)
151
152 /* We ask too much. */
153 object_length_demanded = object_length;
154
155 /* Obtain some data from the application. */
156 status = pima -> ux_device_class_pima_object_data_get(pima, object_handle,
157 object_data + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE,
158 object_offset,
159 object_length_demanded,
160 &object_length_received);
161
162 /* Check status, if we have a problem, we abort. */
163 if (status != UX_SUCCESS)
164 {
165
166 /* We need to inform the host of an error. */
167 break;
168 }
169 else
170 {
171
172 /* Do some sanity check. */
173 if (object_length < object_length_received)
174 {
175
176 /* We have an overflow. Do not proceed. */
177 status = UX_DEVICE_CLASS_PIMA_RC_GENERAL_ERROR;
178 break;
179 }
180
181 /* Adjust the length of the object. */
182 object_length -= object_length_received;
183
184 /* Adjust the offset within the object data. */
185 object_offset += object_length_received;
186
187 /* Adjust the length to be sent. */
188 object_length_received += UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE;
189 }
190 }
191 else
192 {
193
194 /* Calculate the maximum length for the first packet. */
195 object_length_demanded = UX_DEVICE_CLASS_PIMA_TRANSFER_BUFFER_LENGTH;
196
197 /* Can we get that much from the application ? */
198 if (object_length_demanded > object_length)
199
200 /* We ask too much. */
201 object_length_demanded = object_length;
202
203 /* Obtain some data from the application. */
204 status = pima -> ux_device_class_pima_object_data_get(pima, object_handle, object_data, object_offset,
205 object_length_demanded,
206 &object_length_received);
207
208 /* Check status, if we have a problem, we abort. */
209 if (status != UX_SUCCESS)
210 {
211
212 /* We need to inform the host of an error. */
213 break;
214 }
215 else
216 {
217
218 /* Do some sanity check. */
219 if (object_length < object_length_received)
220 {
221
222 /* We have an overflow. Do not proceed. */
223 status = UX_DEVICE_CLASS_PIMA_RC_GENERAL_ERROR;
224 break;
225 }
226
227 /* Adjust the length of the object. */
228 object_length -= object_length_received;
229
230 /* Adjust the offset within the object data. */
231 object_offset += object_length_received;
232 }
233 }
234
235 /* It's canceled, do not proceed. */
236 if (pima -> ux_device_class_pima_state == UX_DEVICE_CLASS_PIMA_PHASE_IDLE)
237 {
238 pima -> ux_device_class_pima_device_status = UX_DEVICE_CLASS_PIMA_RC_OK;
239 return(UX_ERROR);
240 }
241
242 /* Not do transfer, just send the object data to the host. */
243 status = _ux_device_stack_transfer_request(transfer_request,
244 object_length_received, UX_DEVICE_CLASS_PIMA_TRANSFER_BUFFER_LENGTH);
245
246 /* It's canceled, do not proceed. */
247 if (pima -> ux_device_class_pima_state == UX_DEVICE_CLASS_PIMA_PHASE_IDLE)
248 {
249 pima -> ux_device_class_pima_device_status = UX_DEVICE_CLASS_PIMA_RC_OK;
250 return(UX_ERROR);
251 }
252
253 /* Check for the status. We may have had a request to cancel the transaction from the host. */
254 if (status != UX_SUCCESS)
255 {
256
257 /* Check the completion code for transfer abort from the host. */
258 if (transfer_request -> ux_slave_transfer_request_status == UX_TRANSFER_STATUS_ABORT)
259 {
260
261 /* Do not proceed. */
262 return(UX_ERROR);
263 }
264 else
265 {
266
267 /* We need to inform the host of an error. */
268 status = UX_DEVICE_CLASS_PIMA_RC_GENERAL_ERROR;
269 break;
270 }
271 }
272 else
273 {
274
275 /* Update the total length to be sent. */
276 total_length -= object_length_received;
277 }
278 }
279
280 /* Now we return a response. */
281 if (status == UX_SUCCESS)
282 _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0);
283 }
284
285 /* Check if status is OK. */
286 if (status != UX_SUCCESS)
287 {
288
289 /* We need to stall the bulk in pipe. This is the method used by Pima devices to
290 cancel a transaction. */
291 _ux_device_stack_endpoint_stall(pima -> ux_device_class_pima_bulk_in_endpoint);
292 }
293
294 /* Return completion status. */
295 return(status);
296 }
297