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 Stack */
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_stack.h"
30
31
32 #if defined(UX_DEVICE_STANDALONE)
33
34 #define UX_DEVICE_STACK_TRANSFER_STATE_HALT_WAIT (UX_STATE_STACK_STEP + 0)
35 #define UX_DEVICE_STACK_TRANSFER_STATE_TRAN_WAIT (UX_STATE_STACK_STEP + 1)
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _ux_device_stack_transfer_run PORTABLE C */
42 /* 6.1.10 */
43 /* AUTHOR */
44 /* */
45 /* Chaoqiong Xiao, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function performs a USB transaction. On entry the */
50 /* transfer request gives the endpoint pipe selected for this */
51 /* transaction and the parameters associated with the transfer */
52 /* (data payload, length of transaction). */
53 /* */
54 /* It's for standalone mode. */
55 /* */
56 /* INPUT */
57 /* */
58 /* transfer_request Pointer to transfer request */
59 /* slave_length Length returned by host */
60 /* host_length Length asked by host */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* State machine Status to check */
65 /* UX_STATE_NEXT Transfer done, to next state */
66 /* UX_STATE_EXIT Abnormal, to reset state */
67 /* (others) Keep running, waiting */
68 /* */
69 /* CALLS */
70 /* */
71 /* (ux_slave_dcd_function) Slave DCD dispatch function */
72 /* */
73 /* CALLED BY */
74 /* */
75 /* Application */
76 /* Device Stack */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
83 /* */
84 /**************************************************************************/
_ux_device_stack_transfer_run(UX_SLAVE_TRANSFER * transfer_request,ULONG slave_length,ULONG host_length)85 UINT _ux_device_stack_transfer_run(UX_SLAVE_TRANSFER *transfer_request, ULONG slave_length, ULONG host_length)
86 {
87
88 UX_SLAVE_DCD *dcd;
89 UINT status;
90 UINT state;
91 UX_SLAVE_ENDPOINT *endpoint;
92 ULONG device_state;
93
94
95 /* Do we have to skip this transfer? */
96 if (transfer_request -> ux_slave_transfer_request_status_phase_ignore == UX_TRUE)
97 {
98 transfer_request -> ux_slave_transfer_request_completion_code = UX_SUCCESS;
99 transfer_request -> ux_slave_transfer_request_state = UX_STATE_NEXT;
100 return(UX_STATE_NEXT);
101 }
102
103 /* Get the device state. */
104 device_state = _ux_system_slave -> ux_system_slave_device.ux_slave_device_state;
105
106 /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */
107 if (!(device_state == UX_DEVICE_ATTACHED) &&
108 !(device_state == UX_DEVICE_ADDRESSED) &&
109 !(device_state == UX_DEVICE_CONFIGURED))
110 {
111 transfer_request -> ux_slave_transfer_request_completion_code = UX_TRANSFER_NOT_READY;
112 transfer_request -> ux_slave_transfer_request_state = UX_STATE_RESET;
113 return(UX_STATE_EXIT);
114 }
115
116 /* Get the pointer to the DCD. */
117 dcd = &_ux_system_slave -> ux_system_slave_dcd;
118
119 /* Get the endpoint associated with this transaction. */
120 endpoint = transfer_request -> ux_slave_transfer_request_endpoint;
121
122 /* Process states. */
123 state = transfer_request -> ux_slave_transfer_request_state;
124 switch(state)
125 {
126 case UX_STATE_RESET:
127
128 /* Prepare transfer parameters. */
129
130 /* If the endpoint is non Control, check the endpoint direction and set the data phase direction. */
131 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_CONTROL_ENDPOINT)
132 {
133
134 /* Isolate the direction from the endpoint address. */
135 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
136 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT;
137 else
138 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_IN;
139 }
140
141 /* See if we need to force a zero length packet at the end of the transfer.
142 This happens on a DATA IN and when the host requested length is not met
143 and the last packet is on a boundary. If slave_length is zero, then it is
144 a explicit ZLP request, no need to force ZLP. */
145 if ((transfer_request -> ux_slave_transfer_request_phase == UX_TRANSFER_PHASE_DATA_OUT) &&
146 (slave_length != 0) && (host_length != slave_length) &&
147 (slave_length % endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize) == 0)
148 {
149
150 /* If so force Zero Length Packet. */
151 transfer_request -> ux_slave_transfer_request_force_zlp = UX_TRUE;
152 }
153 else
154 {
155
156 /* Condition is not met, do not force a Zero Length Packet. */
157 transfer_request -> ux_slave_transfer_request_force_zlp = UX_FALSE;
158 }
159
160 /* Reset the number of bytes sent/received. */
161 transfer_request -> ux_slave_transfer_request_actual_length = 0;
162
163 /* Determine how many bytes to send in this transaction. We keep track of the original
164 length and have a working length. */
165 transfer_request -> ux_slave_transfer_request_requested_length = slave_length;
166 transfer_request -> ux_slave_transfer_request_in_transfer_length = slave_length;
167
168 /* Save the buffer pointer. */
169 transfer_request -> ux_slave_transfer_request_current_data_pointer =
170 transfer_request -> ux_slave_transfer_request_data_pointer;
171
172 /* Set the transfer to pending. */
173 transfer_request -> ux_slave_transfer_request_status = UX_TRANSFER_STATUS_PENDING;
174
175 /* Next state. */
176 transfer_request -> ux_slave_transfer_request_state = UX_DEVICE_STACK_TRANSFER_STATE_HALT_WAIT;
177
178 /* If trace is enabled, insert this event into the trace buffer. */
179 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_TRANSFER_REQUEST, transfer_request, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
180
181 /* Fall through. */
182 case UX_DEVICE_STACK_TRANSFER_STATE_HALT_WAIT:
183
184 /* If the endpoint is non Control, check the endpoint direction and set the data phase direction. */
185 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_CONTROL_ENDPOINT)
186 {
187
188 /* Return WAIT until halt cleared. */
189 if (endpoint -> ux_slave_endpoint_state == UX_ENDPOINT_HALTED)
190 return(UX_STATE_WAIT);
191
192 }
193
194 /* Next state. */
195 transfer_request -> ux_slave_transfer_request_state = UX_DEVICE_STACK_TRANSFER_STATE_TRAN_WAIT;
196
197 /* Start background transfer immediately. */
198 /* Fall through. */
199 case UX_DEVICE_STACK_TRANSFER_STATE_TRAN_WAIT:
200
201 /* Call the DCD driver transfer function. */
202 /* Transfer state is adjusted inside DCD driver. */
203 status = dcd -> ux_slave_dcd_function(dcd, UX_DCD_TRANSFER_RUN, transfer_request);
204
205 /* Any error case or normal end: reset state for next transfer. */
206 if (status < UX_STATE_WAIT)
207 {
208 UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
209 }
210 break;
211
212 default: /* Error case, return EXIT. */
213 transfer_request -> ux_slave_transfer_request_state = UX_STATE_RESET;
214 return(UX_STATE_EXIT);
215 }
216
217 /* And return the status. */
218 return(status);
219 }
220 #endif
221