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