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 /** USBX Component                                                        */
15 /**                                                                       */
16 /**   Device DPUMP Class                                                  */
17 /**                                                                       */
18 /**************************************************************************/
19 /**************************************************************************/
20 
21 #define UX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "ux_api.h"
27 #include "ux_device_class_dpump.h"
28 #include "ux_device_stack.h"
29 
30 
31 #if defined(UX_DEVICE_STANDALONE)
32 
33 #define UX_DEVICE_CLASS_DPUMP_WRITE_START    (UX_STATE_STEP + 1)
34 #define UX_DEVICE_CLASS_DPUMP_WRITE_WAIT     (UX_STATE_STEP + 2)
35 
36 /**************************************************************************/
37 /*                                                                        */
38 /*  FUNCTION                                               RELEASE        */
39 /*                                                                        */
40 /*    _ux_device_class_dpump_write_run                    PORTABLE C      */
41 /*                                                           6.3.0        */
42 /*  AUTHOR                                                                */
43 /*                                                                        */
44 /*    Chaoqiong Xiao, Microsoft Corporation                               */
45 /*                                                                        */
46 /*  DESCRIPTION                                                           */
47 /*                                                                        */
48 /*    This function writes to the DPUMP class.                            */
49 /*                                                                        */
50 /*    It's for standalone mode.                                           */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    dpump                                   DPUMP class instance        */
55 /*    buffer                                  Buffer data to write        */
56 /*    requested_length                        Bytes to write              */
57 /*    actual_length                           Bytes written               */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    State machine Status to check                                       */
62 /*    UX_STATE_NEXT                         Transfer done, to next state  */
63 /*    UX_STATE_EXIT                         Abnormal, to reset state      */
64 /*    (others)                              Keep running, waiting         */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _ux_device_stack_transfer_request     Request transfer              */
69 /*    _ux_utility_memory_copy               Copy memory                   */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    Application                                                         */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  01-31-2022     Chaoqiong Xiao           Initial Version 6.1.10        */
80 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            added a new mode to manage  */
82 /*                                            endpoint buffer in classes, */
83 /*                                            resulting in version 6.3.0  */
84 /*                                                                        */
85 /**************************************************************************/
_ux_device_class_dpump_write_run(UX_SLAVE_CLASS_DPUMP * dpump,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)86 UINT _ux_device_class_dpump_write_run(UX_SLAVE_CLASS_DPUMP *dpump, UCHAR *buffer,
87                                 ULONG requested_length, ULONG *actual_length)
88 {
89 
90 UX_SLAVE_ENDPOINT           *endpoint;
91 UX_SLAVE_DEVICE             *device;
92 UX_SLAVE_TRANSFER           *transfer_request;
93 UINT                        status;
94 UINT                        zlp = UX_FALSE;
95 UINT                        read_state;
96 
97 
98     /* If trace is enabled, insert this event into the trace buffer.  */
99     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_DPUMP_WRITE, dpump, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
100 
101     /* Get the pointer to the device.  */
102     device =  &_ux_system_slave -> ux_system_slave_device;
103 
104     /* As long as the device is in the CONFIGURED state.  */
105     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
106     {
107 
108         /* Error trap. */
109         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
110 
111         /* If trace is enabled, insert this event into the trace buffer.  */
112         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
113 
114         /* Cannot proceed with command, the interface is down.  */
115         dpump -> ux_device_class_dpump_write_state = UX_STATE_RESET;
116         dpump -> ux_device_class_dpump_write_status = UX_CONFIGURATION_HANDLE_UNKNOWN;
117         return(UX_STATE_EXIT);
118     }
119 
120     /* Locate the OUT endpoint.  */
121     endpoint =  dpump -> ux_slave_class_dpump_bulkin_endpoint;
122 
123     /* Check endpoint. If NULL, we have not yet received the proper SET_INTERFACE command.  */
124     if (endpoint == UX_NULL)
125     {
126         /* Error trap. */
127         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN);
128 
129         dpump -> ux_device_class_dpump_write_state = UX_STATE_RESET;
130         dpump -> ux_device_class_dpump_write_status = UX_ENDPOINT_HANDLE_UNKNOWN;
131         return(UX_STATE_EXIT);
132     }
133 
134     /* All DPUMP reading  are on the endpoint OUT, from the host.  */
135     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
136 
137     /* Handle state cases.  */
138     read_state = dpump -> ux_device_class_dpump_write_state;
139     switch(read_state)
140     {
141     case UX_STATE_RESET:
142         dpump -> ux_device_class_dpump_write_state = UX_DEVICE_CLASS_DPUMP_WRITE_START;
143         dpump -> ux_device_class_dpump_write_status = UX_TRANSFER_NO_ANSWER;
144         dpump -> ux_device_class_dpump_write_buffer = buffer;
145         dpump -> ux_device_class_dpump_write_requested_length = requested_length;
146         dpump -> ux_device_class_dpump_write_actual_length = 0;
147         if (requested_length == 0)
148             zlp = UX_TRUE;
149 
150         /* Fall through.  */
151     case UX_DEVICE_CLASS_DPUMP_WRITE_START:
152 
153         /* Get remaining requested length.  */
154         requested_length = dpump -> ux_device_class_dpump_write_requested_length -
155                         dpump -> ux_device_class_dpump_write_actual_length;
156 
157         /* There is no remaining, we are done.  */
158         if (requested_length == 0 && !zlp)
159         {
160             *actual_length = dpump -> ux_device_class_dpump_write_actual_length;
161             dpump -> ux_device_class_dpump_write_state = UX_STATE_RESET;
162             dpump -> ux_device_class_dpump_write_status = UX_SUCCESS;
163             return(UX_STATE_NEXT);
164         }
165 
166         /* Check if we have enough in the local buffer.  */
167         if (requested_length > UX_DEVICE_CLASS_DPUMP_WRITE_BUFFER_SIZE)
168 
169             /* We have too much to transfer.  */
170             dpump -> ux_device_class_dpump_write_transfer_length = UX_DEVICE_CLASS_DPUMP_WRITE_BUFFER_SIZE;
171 
172         else
173 
174             /* We can proceed with the demanded length.  */
175             dpump -> ux_device_class_dpump_write_transfer_length = requested_length;
176 
177         /* On a out, we copy the buffer to the caller. Not very efficient but it makes the API
178            easier.  */
179         _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
180                             dpump -> ux_device_class_dpump_write_buffer,
181                             dpump -> ux_device_class_dpump_write_transfer_length); /* Use case of memcpy is verified. */
182 
183         /* Next state.  */
184         dpump -> ux_device_class_dpump_write_state = UX_DEVICE_CLASS_DPUMP_WRITE_WAIT;
185         UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
186 
187         /* Fall through.  */
188     case UX_DEVICE_CLASS_DPUMP_WRITE_WAIT:
189 
190         /* Send the request to the device controller.  */
191         status =  _ux_device_stack_transfer_run(transfer_request,
192                             dpump -> ux_device_class_dpump_write_transfer_length,
193                             dpump -> ux_device_class_dpump_write_transfer_length);
194 
195         /* Error case.  */
196         if (status < UX_STATE_NEXT)
197         {
198 
199             dpump -> ux_device_class_dpump_write_state = UX_STATE_RESET;
200             dpump -> ux_device_class_dpump_write_status =
201                 transfer_request -> ux_slave_transfer_request_completion_code;
202             return(UX_STATE_EXIT);
203         }
204 
205         /* Success case.  */
206         if (status == UX_STATE_NEXT)
207         {
208 
209             /* Next buffer address.  */
210             dpump -> ux_device_class_dpump_write_buffer +=
211                     transfer_request -> ux_slave_transfer_request_actual_length;
212 
213             /* Set the length actually received. */
214             dpump -> ux_device_class_dpump_write_actual_length +=
215                     transfer_request -> ux_slave_transfer_request_actual_length;
216 
217             /* Last transfer status.  */
218             dpump -> ux_device_class_dpump_write_status =
219                 transfer_request -> ux_slave_transfer_request_completion_code;
220 
221             /* Update actual length.  */
222             *actual_length = dpump -> ux_device_class_dpump_write_actual_length;
223 
224             /* Check ZLP case.  */
225             if (dpump -> ux_device_class_dpump_write_requested_length == 0)
226             {
227                 dpump -> ux_device_class_dpump_write_state = UX_STATE_RESET;
228                 return(UX_STATE_NEXT);
229             }
230 
231             /* Next state.  */
232             dpump -> ux_device_class_dpump_write_state = UX_DEVICE_CLASS_DPUMP_WRITE_START;
233         }
234 
235         /* Keep waiting.  */
236         return(UX_STATE_WAIT);
237 
238     default: /* Error.  */
239         dpump -> ux_device_class_dpump_write_state = UX_STATE_RESET;
240         break;
241     }
242 
243     /* Error case.  */
244     return(UX_STATE_EXIT);
245 }
246 #endif
247