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