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 /**   EHCI Controller Driver                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_hcd_ehci.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_hcd_ehci_asynchronous_endpoint_create           PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function will create an asynchronous endpoint. The control     */
45 /*    and bulk endpoints fall into this category.                         */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    hcd_ehci                              Pointer to EHCI controller    */
50 /*    endpoint                              Pointer to endpoint           */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    Completion Status                                                   */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_hcd_ehci_ed_obtain                Obtain EHCI ED                */
59 /*    _ux_utility_physical_address          Get physical address          */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    EHCI Controller Driver                                              */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
70 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
71 /*                                            optimized based on compile  */
72 /*                                            definitions,                */
73 /*                                            resulting in version 6.1    */
74 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            fixed compile warnings,     */
76 /*                                            resulting in version 6.1.2  */
77 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            fixed compile warnings,     */
79 /*                                            resulting in version 6.3.0  */
80 /*                                                                        */
81 /**************************************************************************/
_ux_hcd_ehci_asynchronous_endpoint_create(UX_HCD_EHCI * hcd_ehci,UX_ENDPOINT * endpoint)82 UINT  _ux_hcd_ehci_asynchronous_endpoint_create(UX_HCD_EHCI *hcd_ehci, UX_ENDPOINT *endpoint)
83 {
84 
85 UX_DEVICE               *device;
86 UX_EHCI_ED              *ed;
87 UX_EHCI_LINK_POINTER    queue_head;
88 
89 
90     /* We need to take into account the nature of the HCD to define the max size
91        of any transfer in the transfer request.  */
92     endpoint -> ux_endpoint_transfer_request.ux_transfer_request_maximum_length =  UX_EHCI_MAX_PAYLOAD;
93 
94     /* Obtain a ED for this new endpoint. This ED will live as long as the endpoint is active
95        and will be the container for the tds.  */
96     ed =  _ux_hcd_ehci_ed_obtain(hcd_ehci);
97     if (ed == UX_NULL)
98         return(UX_NO_ED_AVAILABLE);
99 
100     /* Attach the ED to the endpoint container.  */
101     endpoint -> ux_endpoint_ed =  (VOID *) ed;
102 
103     /* Now do the opposite, attach the ED container to the physical ED.  */
104     ed -> REF_AS.INTR.ux_ehci_ed_endpoint =  endpoint;
105 
106     /* Set the default MPS Capability info in the ED.  */
107     ed -> ux_ehci_ed_cap0 =  (ULONG)endpoint -> ux_endpoint_descriptor.wMaxPacketSize << UX_EHCI_QH_MPS_LOC;
108 
109     /* Set the default NAK reload count.  */
110     ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_NCR;
111 
112     /* If the device is not high speed and the endpoint is control, then the CEF bit must be set to on.  */
113     device =  endpoint -> ux_endpoint_device;
114     if ((device -> ux_device_speed != UX_HIGH_SPEED_DEVICE) &&
115         ((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_CONTROL_ENDPOINT))
116         ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_CEF;
117 
118     /* Set the device address.  */
119     ed -> ux_ehci_ed_cap0 |=  device -> ux_device_address;
120 
121     /* Add the endpoint address.  */
122     ed -> ux_ehci_ed_cap0 |=  (endpoint -> ux_endpoint_descriptor.bEndpointAddress &
123                                             ~UX_ENDPOINT_DIRECTION) << UX_EHCI_QH_ED_AD_LOC;
124 
125     /* Set the High Bandwidth Pipe Multiplier to 1.  */
126     ed -> ux_ehci_ed_cap1 |=  UX_EHCI_QH_HBPM;
127 
128     /* Set the device speed for full and low speed devices behind a hub the hub address and the
129        port index must be stored in the endpoint.  */
130     switch (device -> ux_device_speed)
131     {
132 
133     case  UX_HIGH_SPEED_DEVICE:
134 
135         ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_HIGH_SPEED;
136         break;
137 
138 
139     case  UX_LOW_SPEED_DEVICE:
140 
141         ed -> ux_ehci_ed_cap0 |=  UX_EHCI_QH_LOW_SPEED;
142         break;
143 
144     case  UX_FULL_SPEED_DEVICE:
145 
146 #if UX_MAX_DEVICES > 1
147         /* The device must be on a hub for this code to execute. We still do a sanity check.  */
148         if (device -> ux_device_parent != UX_NULL)
149         {
150 
151             /* Store the parent hub device address.  */
152             ed -> ux_ehci_ed_cap1 |=  device -> ux_device_parent -> ux_device_address << UX_EHCI_QH_HUB_ADDR_LOC;
153 
154             /* And the port index onto which this device is attached.  */
155             ed -> ux_ehci_ed_cap1 |=  device -> ux_device_port_location << UX_EHCI_QH_PORT_NUMBER_LOC;
156         }
157 #endif
158         break;
159     }
160 
161     /* We need to insert this new endpoint into the asynchronous list. All new EDs are inserted at the
162        end of the list. The current ED will be pointing to the first ED in the list.  */
163     queue_head.void_ptr = _ux_utility_physical_address(hcd_ehci -> ux_hcd_ehci_asynch_first_list);
164     queue_head.value |= UX_EHCI_QH_TYP_QH;
165     ed -> ux_ehci_ed_queue_head =  queue_head.ed_ptr;
166     ed -> ux_ehci_ed_next_ed =     hcd_ehci -> ux_hcd_ehci_asynch_first_list;
167 
168     /* Now we compute the address and the data type to fill the QH pointer with.  */
169     queue_head.void_ptr = _ux_utility_physical_address(ed);
170     queue_head.value |= UX_EHCI_QH_TYP_QH;
171     hcd_ehci -> ux_hcd_ehci_asynch_last_list -> ux_ehci_ed_queue_head = queue_head.ed_ptr;
172     ed -> ux_ehci_ed_previous_ed =  hcd_ehci -> ux_hcd_ehci_asynch_last_list;
173 
174     /* Update the link of the previous ED.  */
175     ed -> ux_ehci_ed_previous_ed -> ux_ehci_ed_next_ed =  ed;
176 
177     /* Remember the new last QH.  */
178     hcd_ehci -> ux_hcd_ehci_asynch_last_list =  ed;
179 
180     /* Return successful completion.  */
181     return(UX_SUCCESS);
182 }
183 
184