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