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 /**   EHCI 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_ehci.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ehci_asynch_td_process                      PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function processes the isochronous, periodic and asynchronous  */
46 /*    lists in search for transfers that occurred in the past             */
47 /*    (micro-)frame.                                                      */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    ed                                    Pointer to ED                 */
52 /*    td                                    Pointer to TD                 */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    UX_EHCI_TD *                          Pointer to TD                 */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    (ux_transfer_request_completion_function) Completion function       */
61 /*    _ux_hcd_ehci_ed_clean                 Clean ED                      */
62 /*    _ux_host_semaphore_put                Put semaphore                 */
63 /*    _ux_utility_virtual_address           Get virtual address           */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    EHCI Controller Driver                                              */
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 /*                                            resulting in version 6.1    */
76 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            refined macros names,       */
78 /*                                            resulting in version 6.1.10 */
79 /*                                                                        */
80 /**************************************************************************/
_ux_hcd_ehci_asynch_td_process(UX_EHCI_ED * ed,UX_EHCI_TD * td)81 UX_EHCI_TD  *_ux_hcd_ehci_asynch_td_process(UX_EHCI_ED *ed, UX_EHCI_TD *td)
82 {
83 
84 UX_TRANSFER     *transfer_request;
85 ULONG           td_residual_length;
86 UINT            td_error;
87 UX_EHCI_TD      *next_td;
88 ULONG           td_element;
89 ULONG           pid;
90 
91 
92     /* If the TD is still active, we know that the transfer has not taken place yet. In this case,
93        the TDs following this one do not need to be process and we return a NULL TD.  */
94     if (td -> ux_ehci_td_control & UX_EHCI_TD_ACTIVE)
95         return(UX_NULL);
96 
97     /* We need the transfer request associated with this TD.  */
98     transfer_request =  td -> ux_ehci_td_transfer_request;
99 
100     /* We have a non active TD, meaning the TD was processed. We should explore the error code and
101        translate it into a generic USBX code.  */
102     td_error =  UX_SUCCESS;
103 
104     /* Check if the TD was halted due to a major error. Note that the error status may contain an error
105        but unless the Halt bit is set, it is not fatal.  */
106     if (td -> ux_ehci_td_control & UX_EHCI_TD_HALTED)
107     {
108 
109         /* Default to STALL.  */
110         td_error =  UX_TRANSFER_STALLED;
111 
112         /* What else could it be ? Buffer underrun/overrun ? */
113         if (td -> ux_ehci_td_control & UX_EHCI_TD_DATA_BUFFER_ERROR)
114             td_error =  UX_TRANSFER_ERROR;
115 
116         /* Babble ? */
117         if (td -> ux_ehci_td_control & UX_EHCI_TD_BABBLE_DETECTED)
118             td_error =  UX_TRANSFER_ERROR;
119 
120         /* Timeout, CRD, Bad PID ... ? */
121         if (td -> ux_ehci_td_control & UX_EHCI_TD_TRANSACTION_ERROR)
122             td_error =  UX_TRANSFER_NO_ANSWER;
123 
124     }
125 
126     /* If there is an error, we should terminate this transfer and clean things.  */
127     if (td_error != UX_SUCCESS)
128     {
129 
130         /* Update the transfer code.  */
131         transfer_request -> ux_transfer_request_completion_code =  td_error;
132 
133         /* Clean the link.  */
134         _ux_hcd_ehci_ed_clean(ed);
135 
136         /* Free the TD that was just treated.  */
137         td -> ux_ehci_td_status =  UX_UNUSED;
138 
139         /* We may do a call back.  */
140         if (transfer_request -> ux_transfer_request_completion_function != UX_NULL)
141             transfer_request -> ux_transfer_request_completion_function(transfer_request);
142 
143         /* Notify the application for debugging purposes.  */
144         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, td_error);
145 
146         /* If trace is enabled, insert this event into the trace buffer.  */
147         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, td_error, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
148 
149         /* Wake up the semaphore for this request.  */
150         _ux_host_semaphore_put(&transfer_request -> ux_transfer_request_semaphore);
151 
152         /* Nothing else to be processed in this queue.  */
153         return(UX_NULL);
154     }
155 
156     /* Update the length of this transaction if the PID is IN or OUT.  */
157     pid =  td -> ux_ehci_td_control & UX_EHCI_PID_MASK;
158     td_residual_length =  0;
159     if ((pid == UX_EHCI_PID_OUT) || (pid == UX_EHCI_PID_IN))
160     {
161 
162         td_residual_length =  (td -> ux_ehci_td_control >> UX_EHCI_TD_LG_LOC) & UX_EHCI_TD_LG_MASK;
163         transfer_request -> ux_transfer_request_actual_length +=  td -> ux_ehci_td_length - td_residual_length;
164     }
165 
166     /* We get here when there is no error on the transfer. It may be that this transfer is not the last
167        one in the link and therefore we process the length received but do not complete the transfer request.  */
168     if (td -> ux_ehci_td_control & UX_EHCI_TD_IOC)
169     {
170 
171         /* Check if this transaction is complete or a short packet occurred, in both case, complete the
172            transaction. In the case of a control endpoint in STATUS phase we complete regardless.  */
173         if ((td_residual_length != 0) ||
174             (transfer_request -> ux_transfer_request_actual_length == transfer_request -> ux_transfer_request_requested_length) ||
175             (td -> ux_ehci_td_phase & UX_EHCI_TD_STATUS_PHASE))
176         {
177 
178             /* Update the transfer code.  */
179             transfer_request -> ux_transfer_request_completion_code =  UX_SUCCESS;
180 
181             /* Clean the link.  */
182             _ux_hcd_ehci_ed_clean(ed);
183 
184             /* Free the TD that was just treated.  */
185             td -> ux_ehci_td_status =  UX_UNUSED;
186 
187             /* We may do a call back.  */
188             if (transfer_request -> ux_transfer_request_completion_function != UX_NULL)
189                 transfer_request -> ux_transfer_request_completion_function(transfer_request);
190 
191             /* Wake up the semaphore for this request.  */
192             _ux_host_semaphore_put(&transfer_request -> ux_transfer_request_semaphore);
193 
194             /* Nothing else to be processed in this queue */
195             return(UX_NULL);
196         }
197     }
198 
199     /* Get the next TD attached to this TD.  */
200     td_element =   (ULONG) td -> ux_ehci_td_link_pointer;
201     td_element &=  ~UX_EHCI_TD_T;
202     next_td =  _ux_utility_virtual_address((VOID *) td_element);
203 
204     /* Free the TD that was just treated.  */
205     td -> ux_ehci_td_status =  UX_UNUSED;
206 
207     /* This TD is now the first TD.  */
208     ed -> ux_ehci_ed_first_td = next_td;
209 
210     /* We get here when we have reached a non completion of a request transfer
211        we need to return the next TD in the linked list.  */
212     return(next_td);
213 }
214 
215