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_object_data_send              PORTABLE C      */
37 /*                                                           6.1.10       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function accepts an object data from 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 /*                                                                        */
59 /*  CALLED BY                                                             */
60 /*                                                                        */
61 /*    Device Storage Class                                                */
62 /*                                                                        */
63 /*  RELEASE HISTORY                                                       */
64 /*                                                                        */
65 /*    DATE              NAME                      DESCRIPTION             */
66 /*                                                                        */
67 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
68 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
69 /*                                            resulting in version 6.1    */
70 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
71 /*                                            updated status handling,    */
72 /*                                            improved cancel flow,       */
73 /*                                            resulting in version 6.1.10 */
74 /*                                                                        */
75 /**************************************************************************/
_ux_device_class_pima_object_data_send(UX_SLAVE_CLASS_PIMA * pima)76 UINT  _ux_device_class_pima_object_data_send(UX_SLAVE_CLASS_PIMA *pima)
77 {
78 
79 UINT                        status;
80 UX_SLAVE_TRANSFER           *transfer_request;
81 ULONG                       transfer_length;
82 UX_SLAVE_CLASS_PIMA_OBJECT  *object;
83 ULONG                       object_handle;
84 UCHAR                       *object_data;
85 ULONG                       object_offset;
86 ULONG                       object_length;
87 ULONG                       total_length;
88 
89     /* Get the last object handle.  The handle used is the last handle used when he host performed a OBJECT_INFO_SEND.  */
90     object_handle =  pima -> ux_device_class_pima_current_object_handle;
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_SEND, 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 OUT).  */
103         pima -> ux_device_class_pima_state = UX_DEVICE_CLASS_PIMA_PHASE_DATA_OUT;
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 received.  */
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 out endpoint.  */
115         transfer_request =  &pima -> ux_device_class_pima_bulk_out_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         /* Assume the host will send all the data.  */
121         while (total_length != 0)
122         {
123 
124             /* Get a data payload.  */
125             status =  _ux_device_stack_transfer_request(transfer_request, UX_DEVICE_CLASS_PIMA_TRANSFER_BUFFER_LENGTH, UX_DEVICE_CLASS_PIMA_TRANSFER_BUFFER_LENGTH);
126 
127             /* It's canceled, do not proceed.  */
128             if (pima -> ux_device_class_pima_state == UX_DEVICE_CLASS_PIMA_PHASE_IDLE)
129             {
130                 pima -> ux_device_class_pima_device_status = UX_DEVICE_CLASS_PIMA_RC_OK;
131                 return(UX_ERROR);
132             }
133 
134             /* Check for the status. We may have had a request to cancel the transaction from the host.  */
135             if (status != UX_SUCCESS)
136             {
137 
138                 /* Check the completion code for transfer abort from the host.  */
139                 if (transfer_request -> ux_slave_transfer_request_status ==  UX_TRANSFER_STATUS_ABORT)
140                 {
141 
142                     /* Do not proceed.  */
143                     return(UX_ERROR);
144 
145                 }
146 
147             else
148                 {
149                     /* We have a transmission error. Do not proceed.  */
150                     status = UX_ERROR;
151                     break;
152 
153                 }
154 
155             }
156 
157             /* Obtain the length of the transaction.  */
158             transfer_length =  transfer_request -> ux_slave_transfer_request_actual_length;
159 
160             /* If this is the first packet, we have to take into account the
161                header.  */
162             if (object_offset == 0)
163             {
164 
165                 /* Do some sanity check.  */
166                 if (object_length < (transfer_length - UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE))
167                 {
168                     /* We have an overflow. Do not proceed.  */
169                     status = UX_ERROR;
170                     break;
171 
172                 }
173 
174                 /* Send the object data to the application.  */
175                 status = pima -> ux_device_class_pima_object_data_send(pima, object_handle, UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_ACTIVE,
176                                                                         object_data + UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE,
177                                                                         object_offset,
178                                                                         (transfer_length - UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE));
179 
180                 /* Check status, if we have a problem, we abort.  */
181                 if (status != UX_SUCCESS)
182                 {
183 
184                     /* We need to inform the host of an error.  */
185                     status =  UX_ERROR;
186                     break;
187                 }
188                 else
189                 {
190 
191                     /* Adjust the remaining length of the object.  */
192                     total_length -= transfer_length;
193 
194                     /* Adjust the length to be sent.  */
195                     object_offset += (transfer_length - UX_DEVICE_CLASS_PIMA_DATA_HEADER_SIZE);
196 
197                 }
198 
199             }
200             else
201             {
202 
203                 /* Do some sanity check.  */
204                 if (object_length < transfer_length)
205                 {
206 
207                     /* We have an overflow. Do not proceed.  */
208                     status = UX_ERROR;
209                     break;
210 
211                 }
212 
213                 /* This is not the first packet, send the object data to the application.  */
214                 status = pima -> ux_device_class_pima_object_data_send(pima, object_handle, UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_ACTIVE,
215                                                                         object_data,
216                                                                         object_offset,
217                                                                         transfer_length);
218 
219                 /* Check status, if we have a problem, we abort.  */
220                 if (status != UX_SUCCESS)
221                 {
222 
223                     /* We need to inform the host of an error.  */
224                     status =  UX_ERROR;
225                     break;
226                 }
227                 else
228                 {
229 
230                     /* Adjust the remaining length of the total object.  */
231                     total_length -= transfer_length;
232 
233                     /* Adjust the length to be sent.  */
234                     object_offset += transfer_length;
235 
236                 }
237 
238             }
239 
240             /* It's canceled, do not proceed.  */
241             if (pima -> ux_device_class_pima_state == UX_DEVICE_CLASS_PIMA_PHASE_IDLE)
242             {
243                 pima -> ux_device_class_pima_device_status = UX_DEVICE_CLASS_PIMA_RC_OK;
244                 return(UX_ERROR);
245             }
246         }
247     }
248 
249     /* Check for status.  */
250     if (status == UX_SUCCESS)
251     {
252 
253         /* Now we return a response with success.  */
254         _ux_device_class_pima_response_send(pima, UX_DEVICE_CLASS_PIMA_RC_OK, 0, 0, 0, 0);
255 
256         /* Make the object transfer completed.  */
257         status = pima -> ux_device_class_pima_object_data_send(pima, object_handle, UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_COMPLETED,
258                                                                                 UX_NULL, 0, 0);
259     }
260     else
261     {
262 
263         /* We need to stall the bulk out pipe.  This is the method used by Pima devices to
264            cancel a transaction.  */
265         _ux_device_stack_endpoint_stall(pima -> ux_device_class_pima_bulk_in_endpoint);
266 
267         /* Make the object transfer non completed.  */
268         status = pima -> ux_device_class_pima_object_data_send(pima, object_handle, UX_DEVICE_CLASS_PIMA_OBJECT_TRANSFER_PHASE_COMPLETED_ERROR,
269                                                                                 UX_NULL, 0, 0);
270 
271     }
272 
273     /* Return completion status.  */
274     return(status);
275 }
276 
277 
278