1 /* This test is designed to test the simple dpump host/device class operation.  */
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 
9 #include "ux_device_class_cdc_acm.h"
10 #include "ux_host_class_cdc_acm.h"
11 
12 #include "ux_device_stack.h"
13 #include "ux_host_stack.h"
14 
15 #include "ux_test_hcd_sim_host.h"
16 #include "ux_test_utility_sim.h"
17 
18 /* Define USBX demo constants.  */
19 
20 #define UX_DEMO_STACK_SIZE      4096
21 #define UX_DEMO_BUFFER_SIZE     2048
22 #define UX_DEMO_RUN             1
23 #define UX_DEMO_MEMORY_SIZE     (64*1024)
24 
25 
26 /* Define the counters used in the demo application...  */
27 
28 static ULONG                           test_error_cases = UX_FALSE;
29 
30 static ULONG                           thread_0_counter;
31 static ULONG                           thread_1_counter;
32 static ULONG                           error_counter;
33 
34 /* Define USBX demo global variables.  */
35 
36 static UX_HOST_CLASS                   *class_driver;
37 static UX_HOST_CLASS_CDC_ACM           *cdc_acm_host_control;
38 static UX_HOST_CLASS_CDC_ACM           *cdc_acm_host_data;
39 static UX_SLAVE_CLASS_CDC_ACM          *cdc_acm_slave;
40 static UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter;
41 
42 static UCHAR                           detect_insertion;
43 static UCHAR                           detect_extraction;
44 
45 
46 static UCHAR device_framework_full_speed[] = {
47 
48     /* Device descriptor     18 bytes
49        0x02 bDeviceClass:    CDC class code
50        0x00 bDeviceSubclass: CDC class sub code
51        0x00 bDeviceProtocol: CDC Device protocol
52 
53        idVendor & idProduct - http://www.linux-usb.org/usb.ids
54     */
55     0x12, 0x01, 0x10, 0x01,
56     0xEF, 0x02, 0x01,
57     0x08,
58     0x84, 0x84, 0x00, 0x00,
59     0x00, 0x01,
60     0x01, 0x02, 03,
61     0x01,
62 
63     /* Configuration 1 descriptor 9 bytes */
64     0x09, 0x02, 0x4b, 0x00,
65     0x02, 0x01, 0x00,
66     0x40, 0x00,
67 
68     /* Interface association descriptor. 8 bytes.  */
69     0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
70 
71     /* Communication Class Interface Descriptor Requirement. 9 bytes.   */
72     0x09, 0x04, 0x00,
73     0x00,
74     0x01,
75     0x02, 0x02, 0x01,
76     0x00,
77 
78     /* Header Functional Descriptor 5 bytes */
79     0x05, 0x24, 0x00,
80     0x10, 0x01,
81 
82     /* ACM Functional Descriptor 4 bytes */
83     0x04, 0x24, 0x02,
84     0x0f,
85 
86     /* Union Functional Descriptor 5 bytes */
87     0x05, 0x24, 0x06,
88     0x00,                          /* Master interface */
89     0x01,                          /* Slave interface  */
90 
91     /* Call Management Functional Descriptor 5 bytes */
92     0x05, 0x24, 0x01,
93     0x03,
94     0x01,                          /* Data interface   */
95 
96     /* Endpoint 0x83 descriptor 7 bytes */
97     0x07, 0x05, 0x83,
98     0x03,
99     0x08, 0x00,
100     0xFF,
101 
102     /* Data Class Interface Descriptor Requirement 9 bytes */
103     0x09, 0x04, 0x01,
104     0x00,
105     0x02,
106     0x0A, 0x00, 0x00,
107     0x00,
108 
109     /* Endpoint 0x02 descriptor 7 bytes */
110     0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */
111     0x02,
112     0x40, 0x00,
113     0x00,
114 
115     /* Endpoint 0x81 descriptor 7 bytes */
116     0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */
117     0x02,
118     0x40, 0x00,
119     0x00,
120 };
121 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed)
122 
123 
124 static UCHAR device_framework_high_speed[] = {
125 
126     /* Device descriptor
127        0x02 bDeviceClass:    CDC class code
128        0x00 bDeviceSubclass: CDC class sub code
129        0x00 bDeviceProtocol: CDC Device protocol
130 
131        idVendor & idProduct - http://www.linux-usb.org/usb.ids
132     */
133     0x12, 0x01, 0x00, 0x02,
134     0xEF, 0x02, 0x01,
135     0x40,
136     0x84, 0x84, 0x00, 0x00,
137     0x00, 0x01,
138     0x01, 0x02, 03,
139     0x01,
140 
141     /* Device qualifier descriptor */
142     0x0a, 0x06, 0x00, 0x02,
143     0x02, 0x00, 0x00,
144     0x40,
145     0x01,
146     0x00,
147 
148     /* Configuration 1 descriptor */
149     0x09, 0x02, 0x4b, 0x00,
150     0x02, 0x01, 0x00,
151     0x40, 0x00,
152 
153     /* Interface association descriptor. */
154     0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
155 
156     /* Communication Class Interface Descriptor Requirement */
157     0x09, 0x04, 0x00,
158     0x00,
159     0x01,
160     0x02, 0x02, 0x01,
161     0x00,
162 
163     /* Header Functional Descriptor */
164     0x05, 0x24, 0x00,
165     0x10, 0x01,
166 
167     /* ACM Functional Descriptor */
168     0x04, 0x24, 0x02,
169     0x0f,
170 
171     /* Union Functional Descriptor */
172     0x05, 0x24, 0x06,
173     0x00,
174     0x01,
175 
176     /* Call Management Functional Descriptor */
177     0x05, 0x24, 0x01,
178     0x00,
179     0x01,
180 
181     /* Endpoint 0x83 descriptor */
182     0x07, 0x05, 0x83,
183     0x03,
184     0x08, 0x00,
185     0xFF,
186 
187     /* Data Class Interface Descriptor Requirement */
188     0x09, 0x04, 0x01,
189     0x00,
190     0x02,
191     0x0A, 0x00, 0x00,
192     0x00,
193 
194     /* Endpoint 0x02 descriptor */
195     0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */
196     0x02,
197     0x40, 0x00,
198     0x00,
199 
200     /* Endpoint 0x81 descriptor */
201     0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */
202     0x02,
203     0x40, 0x00,
204     0x00,
205 };
206 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed)
207 
208 /* String Device Framework :
209     Byte 0 and 1 : Word containing the language ID : 0x0904 for US
210     Byte 2       : Byte containing the index of the descriptor
211     Byte 3       : Byte containing the length of the descriptor string
212 */
213 static UCHAR string_framework[] = {
214 
215     /* Manufacturer string descriptor : Index 1 */
216     0x09, 0x04, 0x01, 0x0c,
217     0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
218     0x6f, 0x67, 0x69, 0x63,
219 
220     /* Product string descriptor : Index 2 */
221     0x09, 0x04, 0x02, 0x0c,
222     0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70,
223     0x44, 0x65, 0x6d, 0x6f,
224 
225     /* Serial Number string descriptor : Index 3 */
226     0x09, 0x04, 0x03, 0x04,
227     0x30, 0x30, 0x30, 0x31
228 };
229 #define STRING_FRAMEWORK_LENGTH sizeof(string_framework)
230 
231 /* Multiple languages are supported on the device, to add
232     a language besides English, the unicode language code must
233     be appended to the language_id_framework array and the length
234     adjusted accordingly. */
235 static UCHAR language_id_framework[] = {
236 
237     /* English. */
238     0x09, 0x04
239 };
240 #define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework)
241 
242 
243 /* Define prototypes for external Host Controller's (HCDs), classes and clients.  */
244 
245 static VOID                test_cdc_instance_activate(VOID  *cdc_instance);
246 static VOID                test_cdc_instance_deactivate(VOID *cdc_instance);
247 
248 static UINT                test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst);
249 
250 UINT                       ux_hcd_sim_initialize(UX_HCD *hcd);
251 
252 static TX_THREAD           tx_test_thread_host_simulation;
253 static TX_THREAD           tx_test_thread_slave_simulation;
254 static void                tx_test_thread_host_simulation_entry(ULONG);
255 static void                tx_test_thread_slave_simulation_entry(ULONG);
256 
257 /* Define the ISR dispatch.  */
258 
259 extern VOID    (*test_isr_dispatch)(void);
260 
261 
262 /* Prototype for test control return.  */
263 
264 void  test_control_return(UINT status);
265 
266 
267 /* Define the ISR dispatch routine.  */
268 
test_isr(void)269 static void    test_isr(void)
270 {
271 
272     /* For further expansion of interrupt-level testing.  */
273 }
274 
275 
error_callback(UINT system_level,UINT system_context,UINT error_code)276 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
277 {
278 
279     /* Failed test.  */
280     if (!test_error_cases)
281     {
282 #ifdef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE
283         /* Generated on device deactivation.  */
284         if (error_code == UX_FUNCTION_NOT_SUPPORTED)
285             return;
286 #endif
287         printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code);
288         test_control_return(1);
289     }
290 }
291 
292 /* Define what the initial system looks like.  */
293 
294 #ifdef CTEST
test_application_define(void * first_unused_memory)295 void test_application_define(void *first_unused_memory)
296 #else
297 void    usbx_ux_host_stack_rh_change_process_test_application_define(void *first_unused_memory)
298 #endif
299 {
300 
301 UINT status;
302 CHAR                            *stack_pointer;
303 CHAR                            *memory_pointer;
304 
305 
306     /* Initialize the free memory pointer.  */
307     stack_pointer = (CHAR *) first_unused_memory;
308     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
309 
310     /* Initialize USBX Memory.  */
311     status =  ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0);
312 
313     /* Check for error.  */
314     if (status != UX_SUCCESS)
315     {
316 
317         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #1\n");
318         test_control_return(1);
319     }
320 
321     /* Register the error callback. */
322     _ux_utility_error_callback_register(error_callback);
323 
324     /* The code below is required for installing the host portion of USBX.  */
325     status =  ux_host_stack_initialize(test_host_change_function);
326 
327     /* Check for error.  */
328     if (status != UX_SUCCESS)
329     {
330 
331         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #2\n");
332         test_control_return(1);
333     }
334 
335     /* Register CDC-ACM class.  */
336     status =  ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry);
337 
338     /* Check for error.  */
339     if (status != UX_SUCCESS)
340     {
341 
342         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #3\n");
343         test_control_return(1);
344     }
345 
346     /* The code below is required for installing the device portion of USBX */
347     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
348                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
349                                        string_framework, STRING_FRAMEWORK_LENGTH,
350                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL);
351 
352     /* Check for error.  */
353     if (status != UX_SUCCESS)
354     {
355 
356         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #5\n");
357         test_control_return(1);
358     }
359 
360     /* Set the parameters for callback when insertion/extraction of a CDC device.  */
361     cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate   =  test_cdc_instance_activate;
362     cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate =  test_cdc_instance_deactivate;
363     cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change    =  UX_NULL;
364 
365     /* Initialize the device cdc class. This class owns both interfaces starting with 0. */
366     status =  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
367                                              1,0,  &cdc_acm_parameter);
368 
369     /* Check for error.  */
370     if (status != UX_SUCCESS)
371     {
372 
373         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #6\n");
374         test_control_return(1);
375     }
376 
377     /* Initialize the simulated device controller.  */
378     status =  _ux_dcd_sim_slave_initialize();
379 
380     /* Check for error.  */
381     if (status != UX_SUCCESS)
382     {
383 
384         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #7\n");
385         test_control_return(1);
386     }
387 
388 #if UX_MAX_HCD > 1
389     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
390     if (status != UX_SUCCESS)
391     {
392         printf("ERROR %x: 0x%x\n", __LINE__, status);
393         test_control_return(1);
394     }
395 #endif
396 
397     /* Register all the USB host controllers available in this system */
398     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,1,0);
399 
400     /* Check for error.  */
401     if (status != UX_SUCCESS)
402     {
403 
404         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #4\n");
405         test_control_return(1);
406     }
407 
408     /* Create the main host simulation thread.  */
409     status =  tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0,
410             stack_pointer, UX_DEMO_STACK_SIZE,
411             20, 20, 1, TX_AUTO_START);
412 
413     /* Check for error.  */
414     if (status != TX_SUCCESS)
415     {
416 
417         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #8\n");
418         test_control_return(1);
419     }
420 
421     /* Create the main demo thread.  */
422     status =  tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0,
423             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
424             20, 20, 1, TX_AUTO_START);
425 
426     /* Check for error.  */
427     if (status != TX_SUCCESS)
428     {
429 
430         printf("Running ux_host_stack_rh_change_process Test........................ ERROR #9\n");
431         test_control_return(1);
432     }
433 }
434 
435 
tx_test_thread_host_simulation_entry(ULONG arg)436 static void  tx_test_thread_host_simulation_entry(ULONG arg)
437 {
438 
439 UINT status;
440 UX_HCD          *hcd;
441 UX_DEVICE       *device;
442 
443     /* Inform user.  */
444     printf("Running ux_host_stack_rh_change_process Test........................ ");
445 
446     ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE);
447 
448     /* Wait connect. */
449     tx_thread_sleep(100);
450     if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL || cdc_acm_slave == UX_NULL)
451     {
452 
453         printf("ERROR #%d: connection not detected\n", __LINE__);
454         test_control_return(1);
455     }
456 
457     status = ux_host_stack_device_get(0, &device);
458     if (status != UX_SUCCESS)
459     {
460 
461         printf("ERROR #%d: fail to get device instance\n", __LINE__);
462         test_control_return(1);
463     }
464 
465 #if UX_MAX_HCD > 1
466     /* Unregister first registered HCD.  */
467     test_error_cases = UX_TRUE;
468     ux_host_stack_hcd_unregister(_ux_system_host_hcd_simulator_name, 0, 0);
469 
470     /* Simulate multiple RH signals. */
471     hcd =  &_ux_system_host -> ux_system_host_hcd_array[1];
472     hcd->ux_hcd_root_hub_signal[0] ++;
473     hcd->ux_hcd_root_hub_signal[0] ++;
474 #else
475 
476     /* Simulate multiple RH signals. */
477     hcd =  &_ux_system_host -> ux_system_host_hcd_array[0];
478     hcd->ux_hcd_root_hub_signal[0] ++;
479     hcd->ux_hcd_root_hub_signal[0] ++;
480 #endif
481 
482     /* Reset detects. */
483     detect_insertion = UX_FALSE;
484     detect_extraction = UX_FALSE;
485     /* Trigger enumeration. */
486     _ux_utility_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
487     /* Wait enough time for enumeration done. */
488     tx_thread_sleep(200);
489     /* Expects extraction and insertion. */
490     if (!detect_extraction)
491     {
492 
493         printf("ERROR #%d: fail to detect extraction\n", __LINE__);
494         error_counter ++;
495     }
496     if (!detect_insertion)
497     {
498 
499         printf("ERROR #%d: fail to detect insertion\n", __LINE__);
500         error_counter ++;
501     }
502 
503     /* Sleep for a tick to make sure everything is complete.  */
504     tx_thread_sleep(1);
505 
506     /* Check for errors from other threads.  */
507     if (error_counter)
508     {
509 
510         /* DPUMP error.  */
511         printf("ERROR #14\n");
512         test_control_return(1);
513     }
514     else
515     {
516 
517         /* Successful test.  */
518         printf("SUCCESS!\n");
519         test_control_return(0);
520     }
521 }
522 
523 
tx_test_thread_slave_simulation_entry(ULONG arg)524 static void  tx_test_thread_slave_simulation_entry(ULONG arg)
525 {
526 
527     while(1)
528     {
529 
530         /* Ensure the dpump class on the device is still alive.  */
531         if (cdc_acm_slave != UX_NULL)
532         {
533 
534             /* Increment thread counter.  */
535             thread_1_counter++;
536         }
537 
538         /* Let other thread run.  */
539         tx_thread_sleep(10);
540     }
541 }
542 
test_cdc_instance_activate(VOID * cdc_instance)543 static VOID  test_cdc_instance_activate(VOID *cdc_instance)
544 {
545 
546     /* Save the CDC instance.  */
547     cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
548 }
549 
test_cdc_instance_deactivate(VOID * cdc_instance)550 static VOID  test_cdc_instance_deactivate(VOID *cdc_instance)
551 {
552 
553     /* Reset the CDC instance.  */
554     cdc_acm_slave = UX_NULL;
555 }
556 
test_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)557 static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
558 {
559 UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst;
560 
561     switch(event)
562     {
563 
564         case UX_DEVICE_INSERTION:
565 
566             detect_insertion = UX_TRUE;
567 
568             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
569                 cdc_acm_host_control = cdc_acm;
570             else
571                 cdc_acm_host_data = cdc_acm;
572             break;
573 
574         case UX_DEVICE_REMOVAL:
575 
576             detect_extraction = UX_TRUE;
577 
578             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
579                 cdc_acm_host_control = UX_NULL;
580             else
581                 cdc_acm_host_data = UX_NULL;
582             break;
583 
584         default:
585             break;
586     }
587     return UX_SUCCESS;
588 }