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