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, &current_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