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 "fx_api.h"
10 
11 #include "ux_device_class_cdc_acm.h"
12 #include "ux_device_stack.h"
13 
14 #include "ux_host_class_cdc_acm.h"
15 
16 #include "ux_test_dcd_sim_slave.h"
17 #include "ux_test_hcd_sim_host.h"
18 #include "ux_test_utility_sim.h"
19 
20 #include "ux_host_stack.h"
21 
22 /* Define constants.  */
23 #define                             UX_DEMO_DEBUG_SIZE  (4096*8)
24 #define                             UX_DEMO_STACK_SIZE  1024
25 #define                             UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1)
26 #define                             UX_DEMO_XMIT_BUFFER_SIZE 512
27 #define                             UX_DEMO_RECEPTION_BUFFER_SIZE 512
28 #define                             UX_DEMO_FILE_BUFFER_SIZE 512
29 #define                             UX_DEMO_RECEPTION_BLOCK_SIZE 64
30 #define                             UX_DEMO_MEMORY_SIZE     (64*1024)
31 #define                             UX_DEMO_FILE_SIZE       (128 * 1024)
32 #define                             UX_RAM_DISK_MEMORY      (256 * 1024)
33 
34 #define     LSB(x) ( (x) & 0x00ff)
35 #define     MSB(x) (((x) & 0xff00) >> 8)
36 
37 /* Configuration descriptor 9 bytes */
38 #define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\
39     /* Configuration 1 descriptor 9 bytes */\
40     0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\
41     (bNumInterfaces), (bConfigurationValue), 0x00,\
42     0x40, 0x00,
43 #define CFG_DESC_LEN 9
44 
45 #define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\
46     /* Interface association descriptor. 8 bytes.  */\
47     0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,\
48     /* Communication Class Interface Descriptor Requirement. 9 bytes.   */\
49     0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\
50     /* Header Functional Descriptor 5 bytes */\
51     0x05, 0x24, 0x00, 0x10, 0x01,\
52     /* ACM Functional Descriptor 4 bytes */\
53     0x04, 0x24, 0x02, 0x0f,\
54     /* Union Functional Descriptor 5 bytes */\
55     0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\
56     /* Call Management Functional Descriptor 5 bytes */\
57     0x05, 0x24, 0x01, 0x03, (bIfc + 1),\
58     /* Endpoint interrupt in descriptor 7 bytes */\
59     0x07, 0x05, (bIntIn), 0x02, 0x40, 0x00, 0x00,\
60     /* Data Class Interface Descriptor Requirement 9 bytes */\
61     0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\
62     /* Endpoint bulk in descriptor 7 bytes */\
63     0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x00,\
64     /* Endpoint bulk out descriptor 7 bytes */\
65     0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x00,
66 #define CDC_IFC_DESC_ALL_LEN (8+ 9+5+4+5+5+7+ 9+7+7)
67 
68 /* Define local/extern function prototypes.  */
69 static VOID                                test_thread_entry(ULONG);
70 static TX_THREAD                           tx_test_thread_host_simulation;
71 static TX_THREAD                           tx_test_thread_slave_simulation;
72 static VOID                                tx_test_thread_host_simulation_entry(ULONG);
73 static VOID                                tx_test_thread_slave_simulation_entry(ULONG);
74 static VOID                                test_cdc_instance_activate(VOID  *cdc_instance);
75 static VOID                                test_cdc_instance_deactivate(VOID *cdc_instance);
76 static VOID                                test_cdc_instance_parameter_change(VOID *cdc_instance);
77 
78 /* Define global data structures.  */
79 static UCHAR                               usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)];
80 static UX_HOST_CLASS                       *class_driver;
81 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_control;
82 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_data;
83 
84 static UX_SLAVE_CLASS_CDC_ACM              *cdc_acm_slave;
85 static UCHAR                               cdc_acm_slave_change;
86 static UX_SLAVE_CLASS_CDC_ACM_PARAMETER    parameter;
87 
88 static ULONG                               error_counter;
89 
90 static ULONG                               error_callback_counter;
91 static UCHAR                               error_callback_ignore;
92 
93 /* Define device framework.  */
94 
95 static unsigned char device_framework_full_speed[] = {
96 
97     /* Device descriptor     18 bytes
98        0x02 bDeviceClass:    CDC class code
99        0x00 bDeviceSubclass: CDC class sub code
100        0x00 bDeviceProtocol: CDC Device protocol
101 
102        idVendor & idProduct - http://www.linux-usb.org/usb.ids
103     */
104     0x12, 0x01, 0x10, 0x01,
105     0xEF, 0x02, 0x01,
106     0x08,
107     0x84, 0x84, 0x00, 0x00,
108     0x00, 0x01,
109     0x01, 0x02, 03,
110     0x01, /* bNumConfigurations */
111 
112     /* Configuration 1 descriptor 9 bytes, total 75 bytes */
113     CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1)
114     CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02)
115 };
116 #define             DEVICE_FRAMEWORK_LENGTH_FULL_SPEED      sizeof(device_framework_full_speed)
117 
118 static unsigned char device_framework_high_speed[] = {
119 
120     /* Device descriptor
121        0x02 bDeviceClass:    CDC class code
122        0x00 bDeviceSubclass: CDC class sub code
123        0x00 bDeviceProtocol: CDC Device protocol
124 
125        idVendor & idProduct - http://www.linux-usb.org/usb.ids
126     */
127     0x12, 0x01, 0x00, 0x02,
128     0xEF, 0x02, 0x01,
129     0x40,
130     0x84, 0x84, 0x00, 0x00,
131     0x00, 0x01,
132     0x01, 0x02, 03,
133     0x01, /* bNumConfigurations */
134 
135     /* Device qualifier descriptor */
136     0x0a, 0x06, 0x00, 0x02,
137     0x02, 0x00, 0x00,
138     0x40,
139     0x01,
140     0x00,
141 
142     /* Configuration 1 descriptor 9 bytes, total 75 bytes */
143     CFG_DESC(CFG_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 1)
144     CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02)
145 };
146 #define             DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED      sizeof(device_framework_high_speed)
147 
148 static unsigned char string_framework[] = {
149 
150     /* Manufacturer string descriptor : Index 1 - "Express Logic" */
151     0x09, 0x04, 0x01, 0x0c,
152     0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
153     0x6f, 0x67, 0x69, 0x63,
154 
155     /* Product string descriptor : Index 2 - "EL Composite device" */
156     0x09, 0x04, 0x02, 0x13,
157     0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f,
158     0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76,
159     0x69, 0x63, 0x65,
160 
161     /* Serial Number string descriptor : Index 3 - "0001" */
162     0x09, 0x04, 0x03, 0x04,
163     0x30, 0x30, 0x30, 0x31
164 };
165 #define             STRING_FRAMEWORK_LENGTH                 sizeof(string_framework)
166 
167 /* Multiple languages are supported on the device, to add
168     a language besides english, the unicode language code must
169     be appended to the language_id_framework array and the length
170     adjusted accordingly. */
171 static unsigned char language_id_framework[] = {
172 
173     /* English. */
174     0x09, 0x04
175 };
176 #define             LANGUAGE_ID_FRAMEWORK_LENGTH            sizeof(language_id_framework)
177 
178 static UX_TEST_SETUP _GetCfgDescr = UX_TEST_SETUP_GetCfgDescr;
179 
180 static UX_TEST_HCD_SIM_ACTION error_on_GetCfgDescr0[] = {
181 /* function, request to match,
182    port action, port status,
183    request action, request EP, request data, request actual length, request status,
184    status, additional callback,
185    no_return */
186 {   UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr,
187         UX_FALSE, UX_TEST_PORT_STATUS_DISC,
188         UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, UX_SUCCESS, /* Length error! */
189         UX_ERROR, UX_NULL},
190 {   0   }
191 };
192 
193 static UX_TEST_HCD_SIM_ACTION length_error_on_GetCfgDescr0[] = {
194 /* function, request to match,
195    port action, port status,
196    request action, request EP, request data, request actual length, request status,
197    status, additional callback,
198    no_return */
199 {   UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr,
200         UX_FALSE, UX_TEST_PORT_STATUS_DISC,
201         UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH - 1, UX_SUCCESS, /* Length error! */
202         UX_SUCCESS, UX_NULL},
203 {   0   }
204 };
205 
206 static UX_TEST_HCD_SIM_ACTION length_error_on_GetCfgDescr1[] = {
207 /* function, request to match,
208    port action, port status,
209    request action, request EP, request data, request actual length, request status,
210    status, additional callback,
211    no_return */
212 {   UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr,
213         UX_FALSE, UX_TEST_PORT_STATUS_DISC,
214         UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0,
215         UX_SUCCESS, UX_NULL,
216         UX_TRUE}, /* bypass */
217 {   UX_HCD_TRANSFER_REQUEST, &_GetCfgDescr,
218         UX_FALSE, UX_TEST_PORT_STATUS_DISC,
219         UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, UX_CONFIGURATION_DESCRIPTOR_LENGTH, UX_SUCCESS, /* Length error! */
220         UX_SUCCESS, UX_NULL},
221 {   0   }
222 };
223 
224 /* Define the ISR dispatch.  */
225 
226 extern VOID    (*test_isr_dispatch)(void);
227 
228 
229 /* Prototype for test control return.  */
230 
231 void  test_control_return(UINT status);
232 
233 
234 /* Define the ISR dispatch routine.  */
235 
test_isr(void)236 static void    test_isr(void)
237 {
238 
239     /* For further expansion of interrupt-level testing.  */
240 }
241 
break_on_cdc_acm_all_ready(VOID)242 static UINT break_on_cdc_acm_all_ready(VOID)
243 {
244     if (cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave)
245         return 1;
246 
247     return 0;
248 }
249 
break_on_removal(VOID)250 static UINT break_on_removal(VOID)
251 {
252 
253 UINT                     status;
254 UX_DEVICE               *device;
255 
256     status = ux_host_stack_device_get(0, &device);
257     if (status == UX_SUCCESS)
258         /* Do not break. */
259         return UX_SUCCESS;
260 
261     return 1;
262 }
263 
test_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)264 static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
265 {
266 
267 UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst;
268 
269     switch(event)
270     {
271 
272         case UX_DEVICE_INSERTION:
273 
274             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
275                 cdc_acm_host_control = cdc_acm;
276             else
277                 cdc_acm_host_data = cdc_acm;
278             break;
279 
280         case UX_DEVICE_REMOVAL:
281 
282             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
283                 cdc_acm_host_control = UX_NULL;
284             else
285                 cdc_acm_host_data = UX_NULL;
286             break;
287 
288         default:
289             break;
290     }
291     return 0;
292 }
293 
test_cdc_instance_activate(VOID * cdc_instance)294 static VOID    test_cdc_instance_activate(VOID *cdc_instance)
295 {
296 
297     /* Save the CDC instance.  */
298     cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
299 }
test_cdc_instance_deactivate(VOID * cdc_instance)300 static VOID    test_cdc_instance_deactivate(VOID *cdc_instance)
301 {
302 
303     /* Reset the CDC instance.  */
304     cdc_acm_slave = UX_NULL;
305 }
306 
test_cdc_instance_parameter_change(VOID * cdc_instance)307 static VOID test_cdc_instance_parameter_change(VOID *cdc_instance)
308 {
309 
310     /* Set CDC parameter change flag. */
311     cdc_acm_slave_change = UX_TRUE;
312 }
313 
test_ux_error_callback(UINT system_level,UINT system_context,UINT error_code)314 static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code)
315 {
316     error_callback_counter ++;
317 
318     if (!error_callback_ignore)
319     {
320         {
321             /* Failed test.  */
322             printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code);
323             // test_control_return(1);
324         }
325     }
326 }
327 
328 /* Define what the initial system looks like.  */
329 
330 #ifdef CTEST
test_application_define(void * first_unused_memory)331 void test_application_define(void *first_unused_memory)
332 #else
333 void usbx_ux_host_class_cdc_acm_deactivate_test_application_define(void *first_unused_memory)
334 #endif
335 {
336 
337 UINT                    status;
338 CHAR *                  stack_pointer;
339 CHAR *                  memory_pointer;
340 
341     printf("Running ux_host_class_cdc_acm_deactivate Test....................... ");
342 
343     /* Initialize the free memory pointer */
344     stack_pointer = (CHAR *) usbx_memory;
345     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
346 
347     /* Initialize USBX Memory */
348     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0);
349     /* Check for error.  */
350     if (status != UX_SUCCESS)
351     {
352 
353         printf("ERROR #%d\n", __LINE__);
354         test_control_return(1);
355     }
356 
357     /* Register the error callback. */
358     _ux_utility_error_callback_register(test_ux_error_callback);
359 
360     /* The code below is required for installing the host portion of USBX */
361     status =  ux_host_stack_initialize(test_host_change_function);
362     if (status != UX_SUCCESS)
363     {
364 
365         printf("ERROR #%d\n", __LINE__);
366         test_control_return(1);
367     }
368 
369     /* Register CDC ACM class */
370     status =  ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry);
371     if (status != UX_SUCCESS)
372     {
373 
374         printf("ERROR #%d\n", __LINE__);
375         test_control_return(1);
376     }
377 
378     /* The code below is required for installing the device portion of USBX. No call back for
379        device status change in this example. */
380     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
381                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
382                                        string_framework, STRING_FRAMEWORK_LENGTH,
383                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
384     if(status!=UX_SUCCESS)
385     {
386 
387         printf("ERROR #%d\n", __LINE__);
388         test_control_return(1);
389     }
390 
391     /* Set the parameters for callback when insertion/extraction of a CDC device.  */
392     parameter.ux_slave_class_cdc_acm_instance_activate   =  test_cdc_instance_activate;
393     parameter.ux_slave_class_cdc_acm_instance_deactivate =  test_cdc_instance_deactivate;
394     parameter.ux_slave_class_cdc_acm_parameter_change    =  test_cdc_instance_parameter_change;
395 
396     /* Initialize the device cdc class. This class owns both interfaces starting with 0. */
397     status =  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
398                                              1,0,  &parameter);
399 
400     if(status!=UX_SUCCESS)
401     {
402 
403         printf("ERROR #%d\n", __LINE__);
404         test_control_return(1);
405     }
406 
407     /* Initialize the simulated device controller.  */
408     status =  _ux_test_dcd_sim_slave_initialize();
409 
410     /* Check for error.  */
411     if (status != TX_SUCCESS)
412     {
413 
414         printf("ERROR #%d\n", __LINE__);
415         test_control_return(1);
416     }
417 
418     /* Register HCD for test */
419     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
420     if (status != UX_SUCCESS)
421     {
422 
423         printf("ERROR #%d\n", __LINE__);
424         test_control_return(1);
425     }
426 
427     /* Create the main host simulation thread.  */
428     status =  tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0,
429             stack_pointer, UX_DEMO_STACK_SIZE,
430             20, 20, 1, TX_AUTO_START);
431 
432     /* Check for error.  */
433     if (status != TX_SUCCESS)
434     {
435 
436         printf("ERROR #%d\n", __LINE__);
437         test_control_return(1);
438     }
439 
440     /* Create the main slave simulation  thread.  */
441     status =  tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0,
442             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
443             20, 20, 1, TX_AUTO_START);
444 
445     /* Check for error.  */
446     if (status != TX_SUCCESS)
447     {
448 
449         printf("ERROR #%d\n", __LINE__);
450         test_control_return(1);
451     }
452 }
453 
tx_test_thread_host_simulation_entry(ULONG arg)454 void  tx_test_thread_host_simulation_entry(ULONG arg)
455 {
456 
457 UINT                                                status;
458 UX_HOST_CLASS_COMMAND                               class_command;
459 UX_CONFIGURATION                                   *configuration;
460 UX_DEVICE                                          *device;
461 UX_INTERFACE                                       *interface;
462 
463     stepinfo("\n");
464 
465     /* Test connect. */
466     stepinfo(">>>>>>>>>>>>>>>> Test connect\n");
467     ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE);
468     ux_test_breakable_sleep(100, break_on_cdc_acm_all_ready);
469     if (!(cdc_acm_host_control && cdc_acm_host_data && cdc_acm_slave))
470     {
471 
472         printf("ERROR #%d: connect fail\n", __LINE__);
473         test_control_return(1);
474     }
475 
476     /* Find device */
477     status = _ux_host_stack_device_get(0, &device);
478     if (status != UX_SUCCESS)
479     {
480 
481         printf("ERROR #%d\n", __LINE__);
482         test_control_return(1);
483     }
484 
485     /* Find configuration */
486     status = _ux_host_stack_device_configuration_get(device, 0, &configuration);
487     if (status != UX_SUCCESS)
488     {
489 
490         printf("ERROR #%d\n", __LINE__);
491         test_control_return(1);
492     }
493 
494     /* Prepare a DEACTIVATE command. */
495     class_command.ux_host_class_command_request   = UX_HOST_CLASS_COMMAND_DEACTIVATE;
496     class_command.ux_host_class_command_instance  = (VOID *)cdc_acm_host_control;
497 
498     /* Get interface. */
499     interface = cdc_acm_host_control -> ux_host_class_cdc_acm_interface;
500 
501     error_callback_ignore = UX_TRUE;
502 
503     /* Simulate semaphore error. */
504     stepinfo(">>>>>>>>>>>>>>>> Test ux_host_class_cdc_acm_deactivate::semaphore_get error\n");
505     _ux_utility_semaphore_delete(&cdc_acm_host_control->ux_host_class_cdc_acm_semaphore);
506     status = interface->ux_interface_class->ux_host_class_entry_function(&class_command);
507     if (status == UX_SUCCESS)
508     {
509 
510         printf("ERROR #%d\n", __LINE__);
511         error_counter ++;
512     }
513 
514     /* Create semaphore. */
515     status =  _ux_utility_semaphore_create(&cdc_acm_host_control -> ux_host_class_cdc_acm_semaphore, "ux_host_class_cdc_acm_semaphore", 1);
516     if (status != UX_SUCCESS)
517     {
518 
519         printf("ERROR #%d\n", __LINE__);
520         test_control_return(1);
521     }
522 
523     stepinfo(">>>>>>>>>>>>>>>> Test ux_host_class_cdc_acm_deactivate: without callback\n");
524     _ux_system_host->ux_system_host_change_function = UX_NULL;
525     ux_test_hcd_sim_host_disconnect();
526     ux_test_breakable_sleep(100, break_on_removal);
527     if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL)
528     {
529 
530         printf("ERROR #%d\n", __LINE__);
531         error_counter ++;
532     }
533 
534     error_callback_ignore = UX_FALSE;
535 
536     stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n");
537 
538     /* Deinitialize the class.  */
539     status =  ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry);
540 
541     /* Deinitialize the device side of usbx.  */
542     _ux_device_stack_uninitialize();
543 
544     /* And finally the usbx system resources.  */
545     _ux_system_uninitialize();
546 
547     stepinfo(">>>>>>>>>>>>>>>> Dump results\n");
548 
549     if (error_counter > 0)
550     {
551 
552         /* Test error.  */
553         printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter);
554         test_control_return(1);
555     }
556 
557     /* Successful test.  */
558     printf("SUCCESS!\n");
559     test_control_return(0);
560 }
561 
tx_test_thread_slave_simulation_entry(ULONG arg)562 void  tx_test_thread_slave_simulation_entry(ULONG arg)
563 {
564 
565     while(1)
566     {
567 
568         /* Sleep so ThreadX on Win32 will delete this thread. */
569         ux_utility_delay_ms(100);
570     }
571 }
572