1 /* This test simulator is designed to simulate ux_hcd_ APIs for test. */
2 
3 #include "tx_api.h"
4 #include "tx_thread.h"
5 
6 #include "ux_api.h"
7 #include "ux_hcd_sim_host.h"
8 
9 #include "ux_test_utility_sim.h"
10 #include "ux_test_hcd_sim_host.h"
11 
12 void  test_control_return(UINT status);
13 
14 ULONG ux_test_port_status = UX_PS_CCS | UX_PS_DS_FS;
15 
16 /* We have a no wait version because in a real world scenario, there is no waiting. */
ux_test_hcd_sim_host_disconnect_no_wait(VOID)17 VOID ux_test_hcd_sim_host_disconnect_no_wait(VOID)
18 {
19 
20 UINT            status;
21 UX_HCD          *hcd = &_ux_system_host -> ux_system_host_hcd_array[0];
22 UX_HCD_SIM_HOST *hcd_sim_host = hcd -> ux_hcd_controller_hardware;
23 
24 
25     /* Port is disconnected. */
26     ux_test_port_status = 0;
27     if (hcd_sim_host != UX_NULL)
28     {
29 #if !defined(UX_HOST_STANDALONE)
30         /* Don't let the timer function run, or else the HCD thread will perform transfer requests. */
31         status = tx_timer_deactivate(&hcd_sim_host -> ux_hcd_sim_host_timer);
32         if (status != TX_SUCCESS)
33         {
34 
35             printf("test_hcd_sim_host #%d, error: %d\n", __LINE__, status);
36             test_control_return(1);
37         }
38 #endif
39     }
40     /* Signal change on the port (HCD0.RH.PORT0). */
41     hcd -> ux_hcd_root_hub_signal[0] = 1;
42     /* Signal detach to host enum thread. */
43     _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
44 }
45 
ux_test_hcd_sim_host_disconnect(VOID)46 VOID ux_test_hcd_sim_host_disconnect(VOID)
47 {
48 
49     ux_test_hcd_sim_host_disconnect_no_wait();
50 
51 #if defined(UX_HOST_STANDALONE)
52     {
53         UX_HCD *hcd = &_ux_system_host -> ux_system_host_hcd_array[0];
54         ULONG n_device = hcd -> ux_hcd_nb_devices;
55         for (unsigned i = 0; i < 20000; i ++)
56         {
57             ux_system_tasks_run();
58             if (hcd -> ux_hcd_nb_devices == 0 ||
59                 hcd -> ux_hcd_nb_devices < n_device)
60                 break;
61         }
62     }
63 #else
64 
65     /* Sleep current thread for enum thread to run. */
66     tx_thread_sleep(100);
67 #endif
68 }
69 
ux_test_hcd_sim_host_connect_no_wait(ULONG speed)70 VOID ux_test_hcd_sim_host_connect_no_wait(ULONG speed)
71 {
72 
73 UINT            status;
74 UX_HCD          *hcd = &_ux_system_host -> ux_system_host_hcd_array[0];
75 UX_HCD_SIM_HOST *hcd_sim_host = hcd -> ux_hcd_controller_hardware;
76 
77 
78     /* Connect with specific speed. */
79     switch(speed)
80     {
81         case UX_LOW_SPEED_DEVICE:
82 
83             ux_test_port_status = UX_PS_CCS | UX_PS_DS_LS;
84             break;
85 
86         case UX_FULL_SPEED_DEVICE:
87 
88             ux_test_port_status = UX_PS_CCS | UX_PS_DS_FS;
89             break;
90 
91         case UX_HIGH_SPEED_DEVICE:
92 
93             ux_test_port_status = UX_PS_CCS | UX_PS_DS_HS;
94             break;
95 
96         default:
97             break;
98     }
99 
100 #if !defined(UX_HOST_STANDALONE)
101     /* Allow the timer function to run, or else the HCD thread won't perform transfer requests. */
102     status = tx_timer_activate(&hcd_sim_host -> ux_hcd_sim_host_timer);
103     if (status != TX_SUCCESS &&
104         /* Was the timer already active? */
105         status != TX_ACTIVATE_ERROR)
106     {
107 
108         printf("test_hcd_sim_host #%d, error code: %d\n", __LINE__, status);
109         test_control_return(1);
110     }
111 #endif
112 
113     /* Signal change on the port (HCD0.RH.PORT0). */
114     _ux_system_host -> ux_system_host_hcd_array -> ux_hcd_root_hub_signal[0] = 1;
115     /* Signal detach to host enum thread. */
116     _ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
117 }
118 
ux_test_hcd_sim_host_connect(ULONG speed)119 VOID ux_test_hcd_sim_host_connect(ULONG speed)
120 {
121 
122     ux_test_hcd_sim_host_connect_no_wait(speed);
123 
124     /* Sleep current thread for enum thread to run. */
125     tx_thread_sleep(100);
126 }
127 
128 /* Fork and modify _ux_hcd_sim_host_port_status_get. */
129 
_ux_hcd_sim_host_port_status_get(UX_HCD_SIM_HOST * hcd_sim_host,ULONG port_index)130 ULONG _ux_hcd_sim_host_port_status_get(UX_HCD_SIM_HOST *hcd_sim_host, ULONG port_index)
131 {
132 
133     /* Check to see if this port is valid on this controller.  */
134     if (hcd_sim_host -> ux_hcd_sim_host_nb_root_hubs < port_index)
135     {
136 
137         /* Error trap. */
138         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_PORT_INDEX_UNKNOWN);
139 
140         /* If trace is enabled, insert this event into the trace buffer.  */
141         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_PORT_INDEX_UNKNOWN, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0)
142 
143         return(UX_PORT_INDEX_UNKNOWN);
144     }
145 
146     /* Return port status.  */
147     return(ux_test_port_status);
148 }
149 
150 static UINT last_function = 0;
151 static char *_func_name[] = {
152     "",
153     "DISABLE_CONTROLLER",
154     "GET_PORT_STATUS",
155     "ENABLE_PORT",
156     "DISABLE_PORT",
157     "POWER_ON_PORT",
158     "POWER_DOWN_PORT",
159     "SUSPEND_PORT",
160     "RESUME_PORT",
161     "RESET_PORT",
162     "GET_FRAME_NUMBER",
163     "SET_FRAME_NUMBER",
164     "TRANSFER_REQUEST",
165     "TRANSFER_ABORT",
166     "CREATE_ENDPOINT",
167     "DESTROY_ENDPOINT",
168     "RESET_ENDPOINT",
169     "PROCESS_DONE_QUEUE"
170 };
171 
172 #if 0 /* Not sure what the purpose of this is. -Nick */
173 UINT _ux_test_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter)
174 {
175 
176 UINT                    status;
177 UCHAR                   act  = 0;
178 UX_TRANSFER            *req;
179 UX_ENDPOINT            *ep;
180 TX_THREAD              *this_thread;
181 UINT                    i;
182 UCHAR                   action_matched;
183 
184 
185 #if 0 /* TODO: Enable/disable HCD entry call display */
186 if (function != last_function)
187 {
188     last_function = function;
189     printf("\n_H %2d(%s) ", function, _func_name[function]);
190 }
191 else
192     printf(".");
193 #endif
194 
195     status = ux_test_cd_handle_action(action, hcd, UX_TEST_CD_TYPE_HCD, function, parameter, &action_matched);
196     if (action_matched)
197     {
198         /* Proceed to next action */
199         action++;
200         if (action->function == 0)
201             action = UX_NULL;
202     }
203 
204     return status;
205 }
206 #endif
207 
_ux_test_hcd_sim_host_dummy_entry(UX_HCD * hcd,UINT function,VOID * parameter)208 UINT _ux_test_hcd_sim_host_dummy_entry(UX_HCD *hcd, UINT function, VOID *parameter)
209 {
210     if (function == UX_HCD_GET_PORT_STATUS)
211         /* Never connected. */
212         return 0;
213 
214     return _ux_hcd_sim_host_entry(hcd, function, parameter);
215 }
216 
_ux_test_hcd_sim_host_entry(UX_HCD * hcd,UINT function,VOID * parameter)217 UINT _ux_test_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter)
218 {
219 
220 UINT                                            status;
221 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   params = { hcd, function, parameter };
222 UX_TEST_ACTION                                  action;
223 ULONG                                           action_taken;
224 
225     /* Perform hooked callbacks.  */
226     action_taken = ux_test_do_hooks_before(UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, &params);
227     if (action_taken & 0x80000000u) /* The hook breaks normal process.  */
228         return(action.status);
229 
230     action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, &params);
231     ux_test_do_action_before(&action, &params);
232 
233     if (ux_test_is_expedient_on())
234     {
235         if (action.matched && !action.do_after)
236         {
237             if (!action.no_return)
238             {
239                 return action.status;
240             }
241         }
242     }
243 
244     status = _ux_hcd_sim_host_entry(hcd, function, parameter);
245 
246     ux_test_do_action_after(&action, &params);
247 
248     if (ux_test_is_expedient_on())
249     {
250         if (action.matched && action.do_after)
251         {
252             if (!action.no_return)
253             {
254                 return action.status;
255             }
256         }
257     }
258 
259     /* Perform hooked callbacks.  */
260     ux_test_do_hooks_after(UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY, &params);
261 
262     /* Return completion status.  */
263     return(status);
264 }
265 
_ux_test_hcd_sim_host_initialize(UX_HCD * hcd)266 UINT  _ux_test_hcd_sim_host_initialize(UX_HCD *hcd)
267 {
268 UINT status;
269 
270     if (ux_utility_name_match((UCHAR*)"dummy", hcd->ux_hcd_name, 5))
271     {
272         /* Use dummy halted */
273         hcd -> ux_hcd_status = UX_HCD_STATUS_DEAD; /* Must not be UX_UNUSED == UX_HCD_STATUS_HALTED */
274         hcd -> ux_hcd_entry_function = _ux_test_hcd_sim_host_dummy_entry;
275         return UX_SUCCESS;
276     }
277 
278     /* Use hcd sim host */
279     status = _ux_hcd_sim_host_initialize(hcd);
280 
281     /* Redirect the entry function */
282     hcd -> ux_hcd_entry_function =  _ux_test_hcd_sim_host_entry;
283 
284     return status;
285 }
286 
ux_test_hcd_sim_host_cleanup(VOID)287 VOID ux_test_hcd_sim_host_cleanup(VOID)
288 {
289 
290     ux_test_port_status = UX_PS_CCS | UX_PS_DS_FS;
291 }
292