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