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