1 /* This test is designed to test the _ux_host_stack_hcd_thread_entry.  */
2 
3 #include <stdio.h>
4 #include "tx_api.h"
5 #include "ux_api.h"
6 #include "ux_system.h"
7 #include "ux_utility.h"
8 #include "ux_host_stack.h"
9 #include "ux_host_class_dpump.h"
10 #include "ux_device_class_dpump.h"
11 
12 
13 /* Define USBX test constants.  */
14 
15 #define UX_TEST_STACK_SIZE      4096
16 #define UX_TEST_BUFFER_SIZE     2048
17 #define UX_TEST_RUN             1
18 #define UX_TEST_MEMORY_SIZE     (64*1024)
19 
20 
21 /* Define the counters used in the test application...  */
22 
23 static ULONG                           thread_0_counter;
24 static ULONG                           thread_1_counter;
25 static ULONG                           error_counter;
26 
27 static ULONG                           hcd_thread_counter[UX_MAX_HCD];
28 
29 static ULONG                           error_callback_ignore = UX_FALSE;
30 
31 
32 /* Define USBX test global variables.  */
33 
34 static unsigned char                   host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
35 static unsigned char                   host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
36 static unsigned char                   slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
37 
38 static UX_HOST_CLASS                   *class_driver;
39 static UX_HOST_CLASS_DPUMP             *dpump;
40 static UX_SLAVE_CLASS_DPUMP            *dpump_slave;
41 
42 
43 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50
44 static UCHAR device_framework_full_speed[] = {
45 
46     /* Device descriptor */
47         0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
48         0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
49         0x00, 0x01,
50 
51     /* Configuration descriptor */
52         0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
53         0x32,
54 
55     /* Interface descriptor */
56         0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99,
57         0x00,
58 
59     /* Endpoint descriptor (Bulk Out) */
60         0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
61 
62     /* Endpoint descriptor (Bulk In) */
63         0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00
64     };
65 
66 
67 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60
68 static UCHAR device_framework_high_speed[] = {
69 
70     /* Device descriptor */
71         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
72         0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
73         0x03, 0x01,
74 
75     /* Device qualifier descriptor */
76         0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
77         0x01, 0x00,
78 
79     /* Configuration descriptor */
80         0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
81         0x32,
82 
83     /* Interface descriptor */
84         0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99,
85         0x00,
86 
87     /* Endpoint descriptor (Bulk Out) */
88         0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00,
89 
90     /* Endpoint descriptor (Bulk In) */
91         0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00
92     };
93 
94     /* String Device Framework :
95      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
96      Byte 2       : Byte containing the index of the descriptor
97      Byte 3       : Byte containing the length of the descriptor string
98     */
99 
100 #define STRING_FRAMEWORK_LENGTH 38
101 static UCHAR string_framework[] = {
102 
103     /* Manufacturer string descriptor : Index 1 */
104         0x09, 0x04, 0x01, 0x0c,
105         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
106         0x6f, 0x67, 0x69, 0x63,
107 
108     /* Product string descriptor : Index 2 */
109         0x09, 0x04, 0x02, 0x0c,
110         0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70,
111         0x44, 0x65, 0x6d, 0x6f,
112 
113     /* Serial Number string descriptor : Index 3 */
114         0x09, 0x04, 0x03, 0x04,
115         0x30, 0x30, 0x30, 0x31
116     };
117 
118 
119     /* Multiple languages are supported on the device, to add
120        a language besides English, the unicode language code must
121        be appended to the language_id_framework array and the length
122        adjusted accordingly. */
123 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
124 static UCHAR language_id_framework[] = {
125 
126     /* English. */
127         0x09, 0x04
128     };
129 
130 
131 /* Define prototypes for external Host Controller's (HCDs), classes and clients.  */
132 
133 static VOID                ux_test_instance_activate(VOID  *dpump_instance);
134 static VOID                ux_test_instance_deactivate(VOID *dpump_instance);
135 
136 UINT                       _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command);
137 UINT                       _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer,
138                                     ULONG requested_length, ULONG *actual_length);
139 UINT                       _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer,
140                                     ULONG requested_length, ULONG *actual_length);
141 
142 static TX_THREAD           ux_test_thread_host_simulation;
143 static TX_THREAD           ux_test_thread_slave_simulation;
144 static void                ux_test_thread_host_simulation_entry(ULONG);
145 static void                ux_test_thread_slave_simulation_entry(ULONG);
146 
147 
148 /* Define the ISR dispatch.  */
149 
150 extern VOID    (*test_isr_dispatch)(void);
151 
152 
153 /* Prototype for test control return.  */
154 
155 void  test_control_return(UINT status);
156 
157 
158 /* Define the ISR dispatch routine.  */
159 
test_isr(void)160 static void    test_isr(void)
161 {
162 
163     /* For further expansion of interrupt-level testing.  */
164 }
165 
166 
error_callback(UINT system_level,UINT system_context,UINT error_code)167 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
168 {
169     if (error_callback_ignore != UX_TRUE &&
170         error_code != UX_CONFIGURATION_HANDLE_UNKNOWN)
171     {
172         /* Failed test.  */
173         printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code);
174         test_control_return(1);
175     }
176 }
177 
_ux_hcd_test_host_entry(UX_HCD * hcd,UINT function,VOID * parameter)178 UINT  _ux_hcd_test_host_entry(UX_HCD *hcd, UINT function, VOID *parameter)
179 {
180 
181 UINT                status;
182 
183 
184     /* Check the status of the controller.  */
185     if (hcd -> ux_hcd_status == UX_UNUSED)
186     {
187 
188         /* Error trap. */
189         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_CONTROLLER_UNKNOWN);
190 
191         /* If trace is enabled, insert this event into the trace buffer.  */
192         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONTROLLER_UNKNOWN, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
193 
194         return(UX_CONTROLLER_UNKNOWN);
195     }
196 
197     hcd_thread_counter[hcd -> ux_hcd_io] ++;
198 
199     /* look at the function and route it.  */
200     switch(function)
201     {
202 
203     case UX_HCD_GET_PORT_STATUS:
204 
205         status =  UX_PORT_INDEX_UNKNOWN;
206         break;
207     case UX_HCD_GET_FRAME_NUMBER:
208     case UX_HCD_DISABLE_CONTROLLER:
209     case UX_HCD_ENABLE_PORT:
210     case UX_HCD_DISABLE_PORT:
211     case UX_HCD_POWER_ON_PORT:
212     case UX_HCD_POWER_DOWN_PORT:
213     case UX_HCD_SUSPEND_PORT:
214     case UX_HCD_RESUME_PORT:
215     case UX_HCD_RESET_PORT:
216     case UX_HCD_SET_FRAME_NUMBER:
217     case UX_HCD_TRANSFER_REQUEST:
218     case UX_HCD_TRANSFER_ABORT:
219     case UX_HCD_CREATE_ENDPOINT:
220     case UX_HCD_DESTROY_ENDPOINT:
221     case UX_HCD_RESET_ENDPOINT:
222     case UX_HCD_PROCESS_DONE_QUEUE:
223 
224         status =  UX_SUCCESS;
225         break;
226 
227 
228     default:
229 
230         /* Error trap. */
231         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_FUNCTION_NOT_SUPPORTED);
232 
233         /* If trace is enabled, insert this event into the trace buffer.  */
234         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
235 
236         /* Unknown request, return an error.  */
237         status =  UX_FUNCTION_NOT_SUPPORTED;
238     }
239 
240     /* Return completion status.  */
241     return(status);
242 }
243 
_ux_hcd_test_host_signal_event(UX_HCD * hcd)244 static void  _ux_hcd_test_host_signal_event(UX_HCD *hcd)
245 {
246     hcd -> ux_hcd_thread_signal ++;
247     _ux_utility_semaphore_put(&_ux_system_host->ux_system_host_hcd_semaphore);
248 }
249 
_ux_hcd_test_host_initialize(UX_HCD * hcd)250 UINT  _ux_hcd_test_host_initialize(UX_HCD *hcd)
251 {
252 
253     /* Initialize the function collector for this HCD.  */
254     hcd -> ux_hcd_entry_function =  _ux_hcd_test_host_entry;
255 
256     /* Set the host controller into the operational state.  */
257     hcd -> ux_hcd_status =  UX_HCD_STATUS_OPERATIONAL;
258 
259     /* Get the number of ports on the controller. The number of ports needs to be reflected both
260        for the generic HCD container and the local sim_host container. In the simulator,
261        the number of ports is hardwired to 1 only.  */
262     hcd -> ux_hcd_nb_root_hubs =  1;
263 
264     /* Something happened on this port. Signal it to the root hub thread.  */
265     hcd -> ux_hcd_root_hub_signal[0] =  1;
266 
267     /* We need to simulate a Root HUB Status Change for the USB stack since the simulator
268        has not root HUB per se.  */
269     _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
270 
271     /* Return successful completion.  */
272     return(UX_SUCCESS);
273 }
274 
275 
276 /* Define what the initial system looks like.  */
277 
278 #ifdef CTEST
test_application_define(void * first_unused_memory)279 void test_application_define(void *first_unused_memory)
280 #else
281 void    usbx_ux_host_stack_hcd_thread_entry_test_application_define(void *first_unused_memory)
282 #endif
283 {
284 
285 UINT status;
286 CHAR                            *stack_pointer;
287 CHAR                            *memory_pointer;
288 UX_SLAVE_CLASS_DPUMP_PARAMETER  parameter;
289 
290 
291     /* Inform user.  */
292     printf("Running _ux_host_stack_hcd_thread_entry Test........................ ");
293 
294     /* Initialize the free memory pointer.  */
295     stack_pointer = (CHAR *) first_unused_memory;
296     memory_pointer = stack_pointer + (UX_TEST_STACK_SIZE * 2);
297 
298     /* Initialize USBX Memory.  */
299     status =  ux_system_initialize(memory_pointer, UX_TEST_MEMORY_SIZE, UX_NULL, 0);
300 
301     /* Check for error.  */
302     if (status != UX_SUCCESS)
303     {
304 
305         printf("ERROR #1\n");
306         test_control_return(1);
307     }
308 
309     /* Register the error callback. */
310     _ux_utility_error_callback_register(error_callback);
311 
312     /* The code below is required for installing the host portion of USBX.  */
313     status =  ux_host_stack_initialize(UX_NULL);
314 
315     /* Check for error.  */
316     if (status != UX_SUCCESS)
317     {
318 
319         printf("ERROR #2\n");
320         test_control_return(1);
321     }
322 
323     /* Register all the host class drivers for this USBX implementation.  */
324     status =  ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry);
325 
326     /* Check for error.  */
327     if (status != UX_SUCCESS)
328     {
329 
330         printf("ERROR #3\n");
331         test_control_return(1);
332     }
333 
334     /* The code below is required for installing the device portion of USBX */
335     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
336                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
337                                        string_framework, STRING_FRAMEWORK_LENGTH,
338                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL);
339 
340     /* Check for error.  */
341     if (status != UX_SUCCESS)
342     {
343 
344         printf("ERROR #5\n");
345         test_control_return(1);
346     }
347 
348     /* Set the parameters for callback when insertion/extraction of a Data Pump device.  */
349     parameter.ux_slave_class_dpump_instance_activate   =  ux_test_instance_activate;
350     parameter.ux_slave_class_dpump_instance_deactivate =  ux_test_instance_deactivate;
351 
352     /* Initialize the device dpump class. The class is connected with interface 0 */
353     status =  ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry,
354                                                1, 0, &parameter);
355 
356     /* Check for error.  */
357     if (status != UX_SUCCESS)
358     {
359 
360         printf("ERROR #6\n");
361         test_control_return(1);
362     }
363 
364     /* Initialize the simulated device controller.  */
365     status =  _ux_dcd_sim_slave_initialize();
366 
367     /* Check for error.  */
368     if (status != UX_SUCCESS)
369     {
370 
371         printf("ERROR #7\n");
372         test_control_return(1);
373     }
374 
375     /* Register all the USB host controllers available in this system */
376     hcd_thread_counter[0] = 0;
377     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
378 
379     /* Check for error.  */
380     if (status != UX_SUCCESS)
381     {
382 
383         printf("ERROR #4\n");
384         test_control_return(1);
385     }
386 
387 #if UX_MAX_HCD > 1
388     /* Register all the USB host controllers available in this system */
389     hcd_thread_counter[1] = 0;
390     status =  ux_host_stack_hcd_register("hcd_test_driver 1", _ux_hcd_test_host_initialize, 1, 0);
391 
392     /* Check for error.  */
393     if (status != UX_SUCCESS)
394     {
395 
396         printf("ERROR #4\n");
397         test_control_return(1);
398     }
399 #endif
400 
401     /* Create the main host simulation thread.  */
402     status =  tx_thread_create(&ux_test_thread_host_simulation, "test host simulation", ux_test_thread_host_simulation_entry, 0,
403             stack_pointer, UX_TEST_STACK_SIZE,
404             20, 20, 1, TX_AUTO_START);
405 
406     /* Check for error.  */
407     if (status != TX_SUCCESS)
408     {
409 
410         printf("ERROR #8\n");
411         test_control_return(1);
412     }
413 }
414 
415 
ux_test_thread_host_simulation_entry(ULONG arg)416 static void  ux_test_thread_host_simulation_entry(ULONG arg)
417 {
418 
419 UINT                status;
420 UX_HOST_CLASS       *class;
421 
422     /* Find the main data pump container.  */
423     status =  ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class);
424 
425     /* Check for error.  */
426     if (status != UX_SUCCESS)
427     {
428 
429         /* DPUMP basic test error.  */
430         printf("ERROR #10\n");
431         test_control_return(1);
432     }
433 
434     /* We get the first instance of the data pump device.  */
435     do
436     {
437 
438         status =  ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump);
439         tx_thread_relinquish();
440     } while (status != UX_SUCCESS);
441 
442     /* We still need to wait for the data pump status to be live.  */
443     while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE)
444     {
445 
446         tx_thread_relinquish();
447     }
448 
449     /* At this point, the data pump class has been found.  */
450 
451 #if UX_MAX_HCD > 1
452     /* Check if thread entry is called once.  */
453     if (hcd_thread_counter[1] != 1)
454     {
455         printf("ERROR #%d, %d\n", __LINE__, hcd_thread_counter[1]);
456         test_control_return(1);
457     }
458 
459     /* Check if thread entry is called.  */
460     _ux_hcd_test_host_signal_event(&_ux_system_host->ux_system_host_hcd_array[1]);
461     _ux_utility_delay_ms(10);
462     if (hcd_thread_counter[1] != 2)
463     {
464         printf("ERROR #%d, %d\n", __LINE__, hcd_thread_counter[1]);
465         test_control_return(1);
466     }
467 
468     /* Check if thread entry is still called when first HCD unregistered.  */
469     error_callback_ignore = UX_TRUE;
470     ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0);
471     _ux_utility_delay_ms(10);
472     if (_ux_system_host->ux_system_host_hcd_array[0].ux_hcd_status == UX_HCD_STATUS_OPERATIONAL)
473     {
474         printf("ERROR #%d, HCD unregister fail\n", __LINE__);
475         test_control_return(1);
476     }
477 
478     _ux_hcd_test_host_signal_event(&_ux_system_host->ux_system_host_hcd_array[1]);
479     _ux_utility_delay_ms(10);
480     if (hcd_thread_counter[1] != 3)
481     {
482         printf("ERROR #%d, %d\n", __LINE__, hcd_thread_counter[1]);
483         test_control_return(1);
484     }
485 #endif
486 
487     /* Sleep for a tick to make sure everything is complete.  */
488     tx_thread_sleep(1);
489 
490     /* Check for errors from other threads.  */
491     if (error_counter)
492     {
493 
494         /* Test error.  */
495         printf("ERROR #14\n");
496         test_control_return(1);
497     }
498     else
499     {
500 
501         /* Successful test.  */
502         printf("SUCCESS!\n");
503         test_control_return(0);
504     }
505 }
506 
ux_test_instance_activate(VOID * dpump_instance)507 static VOID  ux_test_instance_activate(VOID *dpump_instance)
508 {
509 
510     /* Save the DPUMP instance.  */
511     dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance;
512 }
513 
ux_test_instance_deactivate(VOID * dpump_instance)514 static VOID  ux_test_instance_deactivate(VOID *dpump_instance)
515 {
516 
517     /* Reset the DPUMP instance.  */
518     dpump_slave = UX_NULL;
519 }
520 
521