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