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 /** Host Simulator Controller Driver */
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_hcd_sim_host.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_hcd_sim_host_request_isochronous_transfer PORTABLE C */
37 /* 6.1.12 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function performs an isochronous transfer request. */
45 /* */
46 /* INPUT */
47 /* */
48 /* hcd_sim_host Pointer to host controller */
49 /* transfer_request Pointer to transfer request */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* Completion Status */
54 /* */
55 /* CALLS */
56 /* */
57 /* _ux_hcd_sim_host_frame_number_get Get frame number */
58 /* _ux_hcd_sim_host_isochronous_td_obtain Obtain isochronous TD */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* Host Simulator Controller Driver */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
69 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
70 /* resulting in version 6.1 */
71 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
72 /* fixed payload calculation, */
73 /* resulting in version 6.1.9 */
74 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
75 /* added standalone support, */
76 /* resulting in version 6.1.10 */
77 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
78 /* fixed partial transfer, */
79 /* resulting in version 6.1.12 */
80 /* */
81 /**************************************************************************/
_ux_hcd_sim_host_request_isochronous_transfer(UX_HCD_SIM_HOST * hcd_sim_host,UX_TRANSFER * transfer_request)82 UINT _ux_hcd_sim_host_request_isochronous_transfer(UX_HCD_SIM_HOST *hcd_sim_host, UX_TRANSFER *transfer_request)
83 {
84
85 UX_ENDPOINT *endpoint;
86 UX_HCD_SIM_HOST_ISO_TD *data_td;
87 UX_HCD_SIM_HOST_ISO_TD *start_data_td;
88 UX_HCD_SIM_HOST_ISO_TD *next_data_td;
89 UX_HCD_SIM_HOST_ISO_TD *previous_td;
90 UX_HCD_SIM_HOST_ISO_TD *tail_td;
91 UX_HCD_SIM_HOST_ED *ed;
92 ULONG transfer_request_payload_length;
93 ULONG isoch_packet_payload_length;
94 UCHAR * data_pointer;
95 ULONG current_frame_number;
96 ULONG n_trans, packet_size;
97
98
99 /* Get the pointer to the Endpoint. */
100 endpoint = (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
101
102 /* Now get the physical ED attached to this endpoint. */
103 ed = endpoint -> ux_endpoint_ed;
104
105 /* If the transfer_request specifies a max packet length other than the endpoint
106 size, we force the transfer request value into the endpoint. */
107 if (transfer_request -> ux_transfer_request_packet_length == 0)
108 {
109
110 /* For wMaxPacketSize, bits 10..0 specify the maximum packet size (max 1024),
111 bits 12..11 specify the number of additional transactions (max 2),
112 the calculation below will not cause overflow using 32-bit operation.
113 Note wMaxPacketSize validation has been done in ux_host_stack_new_endpoint_create.c,
114 before endpoint creation, so the value can be directly used here. */
115 packet_size = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK;
116 n_trans = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
117 if (n_trans)
118 {
119 n_trans >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
120 n_trans ++;
121 packet_size *= n_trans;
122 }
123 transfer_request -> ux_transfer_request_packet_length = packet_size;
124 }
125
126 /* Remember the packet length. */
127 isoch_packet_payload_length = transfer_request -> ux_transfer_request_packet_length;
128
129 /* Use the TD pointer by ed -> tail for the first TD of this transfer and chain from this one on. */
130 data_td = (UX_HCD_SIM_HOST_ISO_TD *) ((void *) ed -> ux_sim_host_ed_tail_td);
131 previous_td = data_td;
132
133 /* Reset the first obtained data TD in case there is a TD shortage while building the list of TDs. */
134 start_data_td = UX_NULL;
135
136 /* Calculate the frame number to be used to send this payload. If there are no current transfers,
137 we take the current frame number and add a safety value (2-5) to it. If here is pending transactions,
138 we use the frame number stored in the transfer request. */
139 if (ed -> ux_sim_host_ed_tail_td == ed -> ux_sim_host_ed_head_td)
140 {
141
142 _ux_hcd_sim_host_frame_number_get(hcd_sim_host, ¤t_frame_number);
143 ed -> ux_sim_host_ed_frame = current_frame_number + UX_HCD_SIM_HOST_FRAME_DELAY;
144 }
145 else
146 {
147
148 current_frame_number = ed -> ux_sim_host_ed_frame;
149 }
150
151 /* Load the start buffer address and URB length to split the URB in multiple TD transfer. */
152 transfer_request_payload_length = transfer_request -> ux_transfer_request_requested_length;
153 data_pointer = transfer_request -> ux_transfer_request_data_pointer;
154
155 while (transfer_request_payload_length != 0)
156 {
157
158 /* Set the direction of the TD. */
159 if ((transfer_request -> ux_transfer_request_type&UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
160
161 data_td -> ux_sim_host_iso_td_direction = UX_HCD_SIM_HOST_TD_IN;
162 else
163
164 data_td -> ux_sim_host_iso_td_direction = UX_HCD_SIM_HOST_TD_OUT;
165
166 /* Mark the TD with the DATA phase. */
167 data_td -> ux_sim_host_iso_td_status |= UX_HCD_SIM_HOST_TD_DATA_PHASE;
168
169 /* Set the frame number. */
170 ed -> ux_sim_host_ed_frame = current_frame_number;
171
172 /* Set the buffer address. */
173 data_td -> ux_sim_host_iso_td_buffer = data_pointer;
174
175 /* Update the length of the transfer for this TD. */
176 data_td -> ux_sim_host_iso_td_length = UX_MIN(transfer_request_payload_length, isoch_packet_payload_length);
177
178 /* Attach the endpoint and transfer request to the TD. */
179 data_td -> ux_sim_host_iso_td_transfer_request = transfer_request;
180 data_td -> ux_sim_host_iso_td_ed = ed;
181
182 /* Adjust the data payload length and the data payload pointer. */
183 transfer_request_payload_length -= data_td -> ux_sim_host_iso_td_length;
184 data_pointer += data_td -> ux_sim_host_iso_td_length;
185
186 /* Prepare the next frame for the next TD in advance. */
187 current_frame_number++;
188
189 /* Check if there will be another transaction. */
190 if (transfer_request_payload_length != 0)
191 {
192
193 /* Get a new TD to hook this payload. */
194 data_td = _ux_hcd_sim_host_isochronous_td_obtain(hcd_sim_host);
195 if (data_td == UX_NULL)
196 {
197
198 /* If there was already a TD chain in progress, free it. */
199 if (start_data_td != UX_NULL)
200 {
201
202 data_td = start_data_td;
203 while(data_td)
204 {
205
206 next_data_td = data_td -> ux_sim_host_iso_td_next_td;
207 data_td -> ux_sim_host_iso_td_status = UX_UNUSED;
208 data_td = next_data_td;
209 }
210 }
211
212 return(UX_NO_TD_AVAILABLE);
213 }
214
215 /* the first obtained TD in the chain has to be remembered. */
216 if (start_data_td == UX_NULL)
217 start_data_td = data_td;
218
219 /* Attach this new TD to the previous one. */
220 previous_td -> ux_sim_host_iso_td_next_td = data_td;
221 previous_td = data_td;
222 }
223 }
224
225 /* Memorize the next frame number for this ED. */
226 ed -> ux_sim_host_ed_frame = current_frame_number;
227
228 /* At this stage, the Head and Tail in the ED are still the same and the host simulator controller
229 will skip this ED until we have hooked the new tail TD. */
230 tail_td = _ux_hcd_sim_host_isochronous_td_obtain(hcd_sim_host);
231 if (tail_td == UX_NULL)
232 {
233
234 /* If there was already a TD chain in progress, free it. */
235 if (start_data_td != UX_NULL)
236 {
237
238 data_td = start_data_td;
239 while(data_td)
240 {
241
242 next_data_td = data_td -> ux_sim_host_iso_td_next_td;
243 data_td -> ux_sim_host_iso_td_status = UX_UNUSED;
244 data_td = next_data_td;
245 }
246 }
247
248 return(UX_NO_TD_AVAILABLE);
249 }
250
251 /* Attach the tail TD to the last data TD. */
252 data_td -> ux_sim_host_iso_td_next_td = tail_td;
253
254 /* Adjust the ED tail pointer, the controller can now start this transfer
255 at the chosen frame number. */
256 ed -> ux_sim_host_ed_tail_td = (UX_HCD_SIM_HOST_TD *) ((void *) tail_td);
257
258 /* Return successful completion. */
259 return(UX_SUCCESS);
260 }
261
262