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 /** Host Simulator Controller Driver */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define UX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "ux_api.h"
29 #include "ux_hcd_sim_host.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_hcd_sim_host_interrupt_endpoint_create PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function will create an interrupt endpoint. The interrupt */
45 /* endpoint has an interval of operation from 1 to 255. The host */
46 /* has no hardware scheduler but we still build an interrupt tree */
47 /* similar to the host simulator controller. */
48 /* */
49 /* This routine will match the best interval for the host */
50 /* simulator. It will also determine the best node to hook the */
51 /* endpoint based on the load that already exists on the horizontal */
52 /* ED chain. */
53 /* */
54 /* For the ones curious about this coding. The tricky part is to */
55 /* understand how the interrupt matrix is constructed. We have used */
56 /* EDs with the skip bit on to build a frame of anchor EDs. Each ED */
57 /* creates a node for an appropriate combination of interval frequency */
58 /* in the list. */
59 /* */
60 /* After obtaining a pointer to the list with the lowest traffic, we */
61 /* traverse the list from the highest interval until we reach the */
62 /* interval required. At that node, we anchor our real ED to the node */
63 /* and link the ED that was attached to the node to our ED. */
64 /* */
65 /* INPUT */
66 /* */
67 /* hcd_sim_host Pointer to host controller */
68 /* endpoint Pointer to endpoint */
69 /* */
70 /* OUTPUT */
71 /* */
72 /* Completion Status */
73 /* */
74 /* CALLS */
75 /* */
76 /* _ux_hcd_sim_host_ed_obtain Obtain ED */
77 /* _ux_hcd_sim_host_regular_td_obtain Obtain regular TD */
78 /* _ux_hcd_sim_host_least_traffic_list_get Get least traffic list */
79 /* */
80 /* CALLED BY */
81 /* */
82 /* Host Simulator Controller Driver */
83 /* */
84 /* RELEASE HISTORY */
85 /* */
86 /* DATE NAME DESCRIPTION */
87 /* */
88 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
89 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
90 /* resulting in version 6.1 */
91 /* */
92 /**************************************************************************/
_ux_hcd_sim_host_interrupt_endpoint_create(UX_HCD_SIM_HOST * hcd_sim_host,UX_ENDPOINT * endpoint)93 UINT _ux_hcd_sim_host_interrupt_endpoint_create(UX_HCD_SIM_HOST *hcd_sim_host, UX_ENDPOINT *endpoint)
94 {
95
96 UX_HCD_SIM_HOST_ED *ed;
97 UX_HCD_SIM_HOST_ED *ed_list;
98 UX_HCD_SIM_HOST_ED *next_ed;
99 UX_HCD_SIM_HOST_TD *td;
100 UINT interval;
101 UINT interval_index;
102 UINT interval_sim_host;
103
104
105 /* Obtain a ED for this new endpoint. This ED will live as long as
106 the endpoint is active and will be the container for the TDs. */
107 ed = _ux_hcd_sim_host_ed_obtain(hcd_sim_host);
108 if (ed == UX_NULL)
109 return(UX_NO_ED_AVAILABLE);
110
111 /* Obtain a dummy TD for terminating the ED transfer chain. */
112 td = _ux_hcd_sim_host_regular_td_obtain(hcd_sim_host);
113 if (td == UX_NULL)
114 {
115
116 ed -> ux_sim_host_ed_status = UX_UNUSED;
117 return(UX_NO_TD_AVAILABLE);
118 }
119
120 /* Attach the ED to the endpoint container. */
121 endpoint -> ux_endpoint_ed = (VOID *)ed;
122
123 /* Now do the opposite, attach the ED container to the physical ED. */
124 ed -> ux_sim_host_ed_endpoint = endpoint;
125
126 /* Hook the TD to both the tail and head of the ED. */
127 ed -> ux_sim_host_ed_tail_td = td;
128 ed -> ux_sim_host_ed_head_td = td;
129
130 /* Get the list index with the least traffic. */
131 ed_list = _ux_hcd_sim_host_least_traffic_list_get(hcd_sim_host);
132
133 /* Get the interval for the endpoint and match it to a host simulator list. We match anything
134 that is > 32ms to the 32ms interval list, the 32ms list is list 0, 16ms list is 1...
135 the 1ms list is number 5. */
136 interval = endpoint -> ux_endpoint_descriptor.bInterval;
137 interval_index = 1;
138 interval_sim_host = 5;
139 if (interval >= 32)
140 {
141
142 interval_sim_host = 0;
143 }
144 else
145 {
146
147 while (interval_index < 32)
148 {
149
150 if (interval&interval_index)
151 interval_sim_host--;
152 interval_index = interval_index << 1;
153 }
154 }
155
156 /* Now we need to scan the list of eds from the lowest load entry until we reach
157 the appropriate interval node. The depth index is the interval_sim_host value
158 and the 1st entry is pointed by the ED list entry. */
159 while (interval_sim_host--)
160 {
161
162 ed_list = ed_list -> ux_sim_host_ed_next_ed;
163 while (!(ed_list -> ux_sim_host_ed_status & UX_HCD_SIM_HOST_ED_STATIC))
164 ed_list = ed_list -> ux_sim_host_ed_next_ed;
165 }
166
167 /* We found the node entry of the ED pointer that will be the anchor for this interrupt
168 endpoint. Now we attach this endpoint to the anchor and rebuild the chain . */
169 next_ed = ed_list -> ux_sim_host_ed_next_ed;
170 /* Note that if there is a crash here, it is most likely due to an invalid bInterval. */
171 next_ed -> ux_sim_host_ed_previous_ed = ed;
172 ed -> ux_sim_host_ed_next_ed = next_ed;
173 ed -> ux_sim_host_ed_previous_ed = ed_list;
174 ed_list -> ux_sim_host_ed_next_ed = ed;
175
176 /* There is activity in the periodic tree, the scheduler has to be active all the time. */
177 hcd_sim_host -> ux_hcd_sim_host_periodic_scheduler_active++;
178
179 /* Return successful completion. */
180 return(UX_SUCCESS);
181 }
182
183