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 /**   OHCI Controller Driver                                              */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 /* Include necessary system files.  */
25 
26 #define UX_SOURCE_CODE
27 
28 #include "ux_api.h"
29 #include "ux_hcd_ohci.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ohci_request_bulk_transfer                  PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*     This function performs a bulk transfer request. A bulk transfer    */
46 /*     can be larger than the size of the OHCI buffer so it may be        */
47 /*     required to chain multiple tds to accommodate this transfer        */
48 /*     request. A bulk transfer is non blocking, so we return before the  */
49 /*     transfer request is completed.                                     */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    hcd_ohci                              Pointer to OHCI controller    */
54 /*    transfer_request                      Pointer to transfer request   */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    Completion Status                                                   */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _ux_hcd_ohci_register_read            Read OHCI register            */
63 /*    _ux_hcd_ohci_register_write           Write OHCI register           */
64 /*    _ux_hcd_ohci_regular_td_obtain        Get regular TD                */
65 /*    _ux_utility_physical_address          Get physical address          */
66 /*    _ux_utility_virtual_address           Get virtual address           */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    OHCI Controller Driver                                              */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
77 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            resulting in version 6.1    */
79 /*                                                                        */
80 /**************************************************************************/
_ux_hcd_ohci_request_bulk_transfer(UX_HCD_OHCI * hcd_ohci,UX_TRANSFER * transfer_request)81 UINT  _ux_hcd_ohci_request_bulk_transfer(UX_HCD_OHCI *hcd_ohci, UX_TRANSFER *transfer_request)
82 {
83 
84 UX_ENDPOINT     *endpoint;
85 UX_OHCI_TD      *data_td;
86 UX_OHCI_TD      *start_data_td;
87 UX_OHCI_TD      *next_data_td;
88 UX_OHCI_TD      *previous_td;
89 UX_OHCI_TD      *tail_td;
90 UX_OHCI_ED      *ed;
91 ULONG           transfer_request_payload_length;
92 ULONG           bulk_packet_payload_length;
93 UCHAR *         data_pointer;
94 ULONG           ohci_register;
95 ULONG           zlp_flag;
96 
97 
98     /* Get the pointer to the Endpoint.  */
99     endpoint =  (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
100 
101     /* Now get the physical ED attached to this endpoint.  */
102     ed =  endpoint -> ux_endpoint_ed;
103 
104     /* Use the TD pointer by ed -> tail for the first TD of this transfer
105         and chain from this one on.  */
106     data_td =  _ux_utility_virtual_address(ed -> ux_ohci_ed_tail_td);
107     previous_td =  data_td;
108 
109     /* Reset the first obtained data TD in case there is a TD shortage while building the list of tds.  */
110     start_data_td =  0;
111 
112     /* It may take more than one TD if the transfer_request length is more than the
113        maximum length for a OHCI TD (this is irrelevant of the MaxPacketSize value in
114        the endpoint descriptor). OHCI data payload has a maximum size of 4K.  */
115     transfer_request_payload_length =  transfer_request -> ux_transfer_request_requested_length;
116     data_pointer =  transfer_request -> ux_transfer_request_data_pointer;
117 
118     /* Check for ZLP condition.  */
119     if (transfer_request_payload_length == 0)
120 
121         /* We have a zlp condition.  */
122         zlp_flag = UX_TRUE;
123     else
124 
125         /* We do not have a zlp.  */
126         zlp_flag = UX_FALSE;
127 
128     /* Build all necessary TDs.  */
129     while ((transfer_request_payload_length != 0) || zlp_flag == UX_TRUE)
130     {
131 
132         /* Reset ZLP now.  */
133         zlp_flag = UX_FALSE;
134 
135         /* Check if we are exceeding the max payload. */
136         if (transfer_request_payload_length > UX_OHCI_MAX_PAYLOAD)
137 
138             bulk_packet_payload_length =  UX_OHCI_MAX_PAYLOAD;
139         else
140 
141             bulk_packet_payload_length =  transfer_request_payload_length;
142 
143         /* IN transfer ? */
144         if ((transfer_request -> ux_transfer_request_type&UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
145 
146             data_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_IN | UX_OHCI_TD_DEFAULT_DW0;
147         else
148 
149             data_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_OUT | UX_OHCI_TD_DEFAULT_DW0;
150 
151         /* Store the beginning of the buffer address in the TD.  */
152         data_td -> ux_ohci_td_cbp =  _ux_utility_physical_address(data_pointer);
153 
154         /* Store the end buffer address in the TD.  */
155         data_td -> ux_ohci_td_be =  data_td -> ux_ohci_td_cbp + bulk_packet_payload_length - 1;
156 
157         /* Update the length of the transfer for this TD.  */
158         data_td -> ux_ohci_td_length =  bulk_packet_payload_length;
159 
160         /* Attach the endpoint and transfer request to the TD.  */
161         data_td -> ux_ohci_td_transfer_request =  transfer_request;
162         data_td -> ux_ohci_td_ed =  ed;
163 
164         /* Adjust the data payload length and the data payload pointer.  */
165         transfer_request_payload_length -=  bulk_packet_payload_length;
166         data_pointer +=  bulk_packet_payload_length;
167 
168         /* Check if there will be another transaction.  */
169         if (transfer_request_payload_length != 0)
170         {
171 
172             /* Get a new TD to hook this payload.  */
173             data_td =  _ux_hcd_ohci_regular_td_obtain(hcd_ohci);
174 
175             if (data_td == UX_NULL)
176             {
177 
178                 /* If there was already a TD chain in progress, free it.  */
179                 if (start_data_td != UX_NULL)
180                 {
181 
182                     data_td =  start_data_td;
183                     while(data_td)
184                     {
185 
186                         next_data_td =  _ux_utility_virtual_address(data_td -> ux_ohci_td_next_td);
187                         data_td -> ux_ohci_td_status =  UX_UNUSED;
188                         data_td =  next_data_td;
189                     }
190                 }
191 
192                 return(UX_NO_TD_AVAILABLE);
193             }
194 
195             /* the first obtained TD in the chain has to be remembered.  */
196             if (start_data_td == UX_NULL)
197                 start_data_td =  data_td;
198 
199             /* Attach this new TD to the previous one.  */
200             previous_td -> ux_ohci_td_next_td =  _ux_utility_physical_address(data_td);
201             previous_td -> ux_ohci_td_next_td_transfer_request =  data_td;
202             previous_td =  data_td;
203         }
204     }
205 
206     /* At this stage, the Head and Tail in the ED are still the same and the OHCI controller
207        will skip this ED until we have hooked the new tail TD.  */
208     tail_td =  _ux_hcd_ohci_regular_td_obtain(hcd_ohci);
209     if (tail_td == UX_NULL)
210     {
211 
212         /* If there was already a TD chain in progress, free it.  */
213         if (start_data_td != UX_NULL)
214         {
215 
216             data_td =  start_data_td;
217             while(data_td)
218             {
219 
220                 next_data_td =  _ux_utility_virtual_address(data_td -> ux_ohci_td_next_td);
221                 data_td -> ux_ohci_td_status =  UX_UNUSED;
222                 data_td =  next_data_td;
223             }
224         }
225 
226         return(UX_NO_TD_AVAILABLE);
227     }
228 
229     /* Attach the tail TD to the last data TD.  */
230     data_td -> ux_ohci_td_next_td =  _ux_utility_physical_address(tail_td);
231 
232     /* Store the new tail TD.  */
233     ed -> ux_ohci_ed_tail_td =  _ux_utility_physical_address(tail_td);
234 
235     /* Now, we must tell the OHCI controller that there is something in the
236        bulk queue.  */
237     ohci_register =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_COMMAND_STATUS);
238     ohci_register |=  OHCI_HC_CS_BLF;
239     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_COMMAND_STATUS, ohci_register);
240 
241     /* Return successful completion.  */
242     return(UX_SUCCESS);
243 }
244 
245