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 /**   Host Simulator Controller Driver                                    */
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_hcd_sim_host.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _ux_hcd_sim_host_request_bulk_transfer              PORTABLE C      */
36 /*                                                           6.1.3        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*     This function performs a bulk transfer request. A bulk transfer    */
44 /*     can be larger than the size of the sim_host buffer so it may be    */
45 /*     required to chain multiple TDs to accommodate this transfer        */
46 /*     request. A bulk transfer is non blocking, so we return before the  */
47 /*     transfer request is completed.                                     */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    hcd_sim_host                          Pointer to host controller    */
52 /*    transfer_request                      Pointer to transfer request   */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    Completion Status                                                   */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _ux_hcd_sim_host_regular_td_obtain    Obtain regular TD             */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    Host Simulator Controller Driver                                    */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
71 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*  12-31-2020     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            fixed ZLP sending,          */
75 /*                                            resulting in version 6.1.3  */
76 /*                                                                        */
77 /**************************************************************************/
_ux_hcd_sim_host_request_bulk_transfer(UX_HCD_SIM_HOST * hcd_sim_host,UX_TRANSFER * transfer_request)78 UINT  _ux_hcd_sim_host_request_bulk_transfer(UX_HCD_SIM_HOST *hcd_sim_host, UX_TRANSFER *transfer_request)
79 {
80 
81 UX_ENDPOINT             *endpoint;
82 UX_HCD_SIM_HOST_TD      *data_td;
83 UX_HCD_SIM_HOST_TD      *start_data_td;
84 UX_HCD_SIM_HOST_TD      *next_data_td;
85 UX_HCD_SIM_HOST_TD      *previous_td;
86 UX_HCD_SIM_HOST_TD      *tail_td;
87 UX_HCD_SIM_HOST_ED      *ed;
88 ULONG                   transfer_request_payload_length;
89 ULONG                   bulk_packet_payload_length;
90 UCHAR *                 data_pointer;
91 
92 
93     /* Get the pointer to the Endpoint.  */
94     endpoint =  (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
95 
96     /* Now get the physical ED attached to this endpoint.  */
97     ed =  endpoint -> ux_endpoint_ed;
98 
99     /* Use the TD pointer by ed -> tail for the first TD of this transfer
100        and chain from this one on.  */
101     data_td =  ed -> ux_sim_host_ed_tail_td;
102     previous_td =  data_td;
103 
104     /* Reset the first obtained data TD in case there is a TD shortage while building
105        the list of TDs.  */
106     start_data_td =  0;
107 
108     /* It may take more than one TD if the transfer_request length is more than the
109        maximum length for a host simulator TD (this is irrelevant of the MaxPacketSize value
110        in the endpoint descriptor). Host simulator data payload has a maximum size of 4K.  */
111     transfer_request_payload_length =  transfer_request -> ux_transfer_request_requested_length;
112     data_pointer =  transfer_request -> ux_transfer_request_data_pointer;
113 
114     do
115     {
116 
117         if (transfer_request_payload_length > UX_HCD_SIM_HOST_MAX_PAYLOAD)
118 
119             bulk_packet_payload_length =  UX_HCD_SIM_HOST_MAX_PAYLOAD;
120         else
121 
122             bulk_packet_payload_length =  transfer_request_payload_length;
123 
124         /* Store the beginning of the buffer address in the TD.  */
125         data_td -> ux_sim_host_td_buffer =  data_pointer;
126 
127         /* Update the length of the transfer for this TD.  */
128         data_td -> ux_sim_host_td_length =  bulk_packet_payload_length;
129 
130         /* Attach the endpoint and transfer_request to the TD.  */
131         data_td -> ux_sim_host_td_transfer_request =  transfer_request;
132         data_td -> ux_sim_host_td_ed =  ed;
133 
134         /* Adjust the data payload length and the data payload pointer.  */
135         transfer_request_payload_length -=  bulk_packet_payload_length;
136         data_pointer +=  bulk_packet_payload_length;
137 
138         /* The direction of the transaction is set in the TD.  */
139         if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
140 
141             data_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_IN;
142         else
143             data_td -> ux_sim_host_td_direction =  UX_HCD_SIM_HOST_TD_OUT;
144 
145         /* Mark the TD with the DATA phase.  */
146         data_td -> ux_sim_host_td_status |=  UX_HCD_SIM_HOST_TD_DATA_PHASE;
147 
148         /* The Toggle value is in the ED.  */
149         data_td -> ux_sim_host_td_toggle =  UX_HCD_SIM_HOST_TD_TOGGLE_FROM_ED;
150 
151         /* Check if there will be another transaction.  */
152         if (transfer_request_payload_length != 0)
153         {
154 
155             /* Get a new TD to hook this payload.  */
156             data_td =  _ux_hcd_sim_host_regular_td_obtain(hcd_sim_host);
157             if (data_td == UX_NULL)
158             {
159 
160                 /* If there was already a TD chain in progress, free it.  */
161                 if (start_data_td != UX_NULL)
162                 {
163 
164                     data_td =  start_data_td;
165                     while (data_td)
166                     {
167 
168                         next_data_td =  data_td -> ux_sim_host_td_next_td;
169                         data_td -> ux_sim_host_td_status =  UX_UNUSED;
170                         data_td =  next_data_td;
171                     }
172                 }
173 
174                 return(UX_NO_TD_AVAILABLE);
175             }
176 
177             /* the first obtained TD in the chain has to be remembered.  */
178             if (start_data_td == UX_NULL)
179                 start_data_td =  data_td;
180 
181             /* Attach this new TD to the previous one.  */
182             previous_td -> ux_sim_host_td_next_td =  data_td;
183             previous_td -> ux_sim_host_td_next_td_transfer_request =  data_td;
184             previous_td =  data_td;
185         }
186     } while (transfer_request_payload_length != 0);
187 
188     /* At this stage, the Head and Tail in the ED are still the same and the host simulator
189        controller will skip this ED until we have hooked the new tail TD.  */
190     tail_td =  _ux_hcd_sim_host_regular_td_obtain(hcd_sim_host);
191     if (tail_td == UX_NULL)
192     {
193 
194         /* If there was already a TD chain in progress, free it.  */
195         if (start_data_td != UX_NULL)
196         {
197 
198             data_td =  start_data_td;
199             while (data_td)
200             {
201 
202                 next_data_td =  data_td -> ux_sim_host_td_next_td;
203                 data_td -> ux_sim_host_td_status =  UX_UNUSED;
204                 data_td =  next_data_td;
205             }
206         }
207 
208         return(UX_NO_TD_AVAILABLE);
209     }
210 
211     /* Attach the tail TD to the last data TD.  */
212     data_td -> ux_sim_host_td_next_td =  tail_td;
213 
214     /* Store the new tail TD.  */
215     ed -> ux_sim_host_ed_tail_td =  tail_td;
216 
217     /* Now we can tell the scheduler to wake up.  */
218     hcd_sim_host -> ux_hcd_sim_host_queue_empty =  UX_FALSE;
219 
220     /* Return successful completion.  */
221     return(UX_SUCCESS);
222 }
223 
224