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 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_stack_transfer_request PORTABLE C */
36 /* 6.1.10 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function performs a USB transaction. On entry the */
44 /* transfer request gives the endpoint pipe selected for this */
45 /* transaction and the parameters associated with the transfer */
46 /* (data payload, length of transaction). */
47 /* */
48 /* INPUT */
49 /* */
50 /* transfer_request Pointer to transfer request */
51 /* slave_length Length returned by host */
52 /* host_length Length asked by host */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* Completion Status */
57 /* */
58 /* CALLS */
59 /* */
60 /* (ux_slave_dcd_function) Slave DCD dispatch function */
61 /* _ux_utility_delay_ms Delay ms */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* Application */
66 /* Device Stack */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
73 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
74 /* used UX prefix to refer to */
75 /* TX symbols instead of using */
76 /* them directly, */
77 /* resulting in version 6.1 */
78 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
79 /* added standalone support, */
80 /* resulting in version 6.1.10 */
81 /* */
82 /**************************************************************************/
_ux_device_stack_transfer_request(UX_SLAVE_TRANSFER * transfer_request,ULONG slave_length,ULONG host_length)83 UINT _ux_device_stack_transfer_request(UX_SLAVE_TRANSFER *transfer_request,
84 ULONG slave_length,
85 ULONG host_length)
86 {
87 #if defined(UX_DEVICE_STANDALONE)
88 UINT status;
89
90 /* Start a transfer request without waiting it end. */
91 UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
92 status = _ux_device_stack_transfer_run(transfer_request, slave_length, host_length);
93 if (status == UX_STATE_LOCK)
94 return(UX_BUSY);
95 if (status < UX_STATE_NEXT)
96 return(transfer_request -> ux_slave_transfer_request_completion_code);
97
98 /* Started/done, things will be done in BG */
99 return(UX_SUCCESS);
100 #else
101 UX_INTERRUPT_SAVE_AREA
102
103 UX_SLAVE_DCD *dcd;
104 UINT status;
105 UX_SLAVE_ENDPOINT *endpoint;
106 ULONG device_state;
107
108
109 /* Do we have to skip this transfer? */
110 if (transfer_request -> ux_slave_transfer_request_status_phase_ignore == UX_TRUE)
111 return(UX_SUCCESS);
112
113 /* Disable interrupts to prevent the disconnection ISR from preempting us
114 while we check the device state and set the transfer status. */
115 UX_DISABLE
116
117 /* Get the device state. */
118 device_state = _ux_system_slave -> ux_system_slave_device.ux_slave_device_state;
119
120 /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */
121 if ((device_state == UX_DEVICE_ATTACHED) || (device_state == UX_DEVICE_ADDRESSED)
122 || (device_state == UX_DEVICE_CONFIGURED))
123
124 /* Set the transfer to pending. */
125 transfer_request -> ux_slave_transfer_request_status = UX_TRANSFER_STATUS_PENDING;
126
127 else
128 {
129
130 /* The device is in an invalid state. Restore interrupts and return error. */
131 UX_RESTORE
132 return(UX_TRANSFER_NOT_READY);
133 }
134
135 /* Restore interrupts. */
136 UX_RESTORE
137
138 /* If trace is enabled, insert this event into the trace buffer. */
139 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_TRANSFER_REQUEST, transfer_request, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
140
141 /* Get the pointer to the DCD. */
142 dcd = &_ux_system_slave -> ux_system_slave_dcd;
143
144 /* Get the endpoint associated with this transaction. */
145 endpoint = transfer_request -> ux_slave_transfer_request_endpoint;
146
147 /* If the endpoint is non Control, check the endpoint direction and set the data phase direction. */
148 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_CONTROL_ENDPOINT)
149 {
150
151 /* Check if the endpoint is STALLED. In this case, we must refuse the transaction until the endpoint
152 has been reset by the host. */
153 while (endpoint -> ux_slave_endpoint_state == UX_ENDPOINT_HALTED)
154
155 /* Wait for 100ms for endpoint to be reset by a CLEAR_FEATURE command. */
156 _ux_utility_delay_ms(100);
157
158 /* Isolate the direction from the endpoint address. */
159 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
160 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT;
161 else
162 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_IN;
163 }
164
165 /* See if we need to force a zero length packet at the end of the transfer.
166 This happens on a DATA IN and when the host requested length is not met
167 and the last packet is on a boundary. If slave_length is zero, then it is
168 a explicit ZLP request, no need to force ZLP. */
169 if ((transfer_request -> ux_slave_transfer_request_phase == UX_TRANSFER_PHASE_DATA_OUT) &&
170 (slave_length != 0) && (host_length != slave_length) &&
171 (slave_length % endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize) == 0)
172 {
173
174 /* If so force Zero Length Packet. */
175 transfer_request -> ux_slave_transfer_request_force_zlp = UX_TRUE;
176 }
177 else
178 {
179
180 /* Condition is not met, do not force a Zero Length Packet. */
181 transfer_request -> ux_slave_transfer_request_force_zlp = UX_FALSE;
182 }
183
184 /* Reset the number of bytes sent/received. */
185 transfer_request -> ux_slave_transfer_request_actual_length = 0;
186
187 /* Determine how many bytes to send in this transaction. We keep track of the original
188 length and have a working length. */
189 transfer_request -> ux_slave_transfer_request_requested_length = slave_length;
190 transfer_request -> ux_slave_transfer_request_in_transfer_length = slave_length;
191
192 /* Save the buffer pointer. */
193 transfer_request -> ux_slave_transfer_request_current_data_pointer =
194 transfer_request -> ux_slave_transfer_request_data_pointer;
195
196 /* Call the DCD driver transfer function. */
197 status = dcd -> ux_slave_dcd_function(dcd, UX_DCD_TRANSFER_REQUEST, transfer_request);
198
199 /* And return the status. */
200 return(status);
201
202 #endif
203 }
204
205