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