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