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