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