1 /* This file tests the
2  * _ux_device_class_hid_control_request
3  * _ux_device_class_hid_interrupt_thread
4  */
5 
6 #include "usbx_test_common_hid.h"
7 
8 #include "ux_test_dcd_sim_slave.h"
9 #include "ux_test_hcd_sim_host.h"
10 #include "ux_test_utility_sim.h"
11 
12 #include "ux_host_class_hid_mouse.h"
13 #include "ux_host_class_hid_keyboard.h"
14 
15 #include "ux_host_stack.h"
16 
17 #define DUMMY_USBX_MEMORY_SIZE          (64*1024)
18 
19 static UCHAR                            dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE];
20 
21 static UX_SLAVE_CLASS_HID               *slave_hid = UX_NULL;
22 static UX_SLAVE_CLASS_HID_EVENT         slave_hid_event;
23 
24 #define HOST_BUFFER_LENGTH              32
25 
26 static UCHAR                            host_buffer[HOST_BUFFER_LENGTH];
27 static ULONG                            host_buffer_length;
28 
29 static UCHAR hid_report_descriptor[] = {
30 
31     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
32     0x09, 0x06,                    // USAGE (Keyboard)
33     0xa1, 0x01,                    // COLLECTION (Application)
34     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
35     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
36     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
37     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
38     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
39     0x75, 0x01,                    //   REPORT_SIZE (1)
40     0x95, 0x08,                    //   REPORT_COUNT (8)
41     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
42     0x95, 0x01,                    //   REPORT_COUNT (1)
43     0x75, 0x08,                    //   REPORT_SIZE (8)
44     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
45     0x95, 0x05,                    //   REPORT_COUNT (5)
46     0x75, 0x01,                    //   REPORT_SIZE (1)
47     0x05, 0x08,                    //   USAGE_PAGE (LEDs)
48     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
49     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
50     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
51     0x95, 0x01,                    //   REPORT_COUNT (1)
52     0x75, 0x03,                    //   REPORT_SIZE (3)
53     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
54     0x95, 0x06,                    //   REPORT_COUNT (6)
55     0x75, 0x08,                    //   REPORT_SIZE (8)
56     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
57     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
58     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
59     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
60     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
61     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
62     0xc0                           // END_COLLECTION
63 };
64 #define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0])
65 
66 /* Configuration descriptor 9 bytes */
67 #define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\
68     /* Configuration 1 descriptor 9 bytes */\
69     0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\
70     (bNumInterfaces), (bConfigurationValue), 0x00,\
71     0x40, 0x00,
72 #define CFG_DESC_LEN 9
73 
74 /* HID Mouse interface descriptors 9+9+7=25 bytes */
75 #define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa)     \
76     /* Interface descriptor */\
77     0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\
78     /* HID descriptor */\
79     0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\
80     MSB(HID_REPORT_LENGTH),\
81     /* Endpoint descriptor (Interrupt) */\
82     0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08,
83 #define HID_MOUSE_IFC_DESC_ALL_LEN 25
84 
85 /* HID Mouse interface descriptors 9+9+7+7=32 bytes */
86 #define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type)     \
87     /* Interface descriptor */\
88     0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\
89     /* HID descriptor */\
90     0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\
91     MSB(HID_REPORT_LENGTH),\
92     /* Endpoint descriptor */\
93     0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\
94     /* Endpoint descriptor */\
95     0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08,
96 #define HID_TEST_IFC_DESC_ALL_LEN 32
97 
98 static UCHAR device_framework_full_speed[] = {
99 
100     /* Device descriptor @ 0  */
101     0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
102     0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
103     0x00, 0x01,
104 
105     /* Configuration descriptor @ 18  */
106     CFG_DESC(CFG_DESC_LEN+2*HID_TEST_IFC_DESC_ALL_LEN, 2, 1)
107     /* Interrupt IN @ 1st */
108     HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3)
109     /* HID interface but no interrupt IN */
110     HID_TEST_IFC_DESC_ALL(1, 0x84, 2, 0x03, 3)
111 };
112 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed)
113 #define DEVICE_FRAMEWORK_OFFSET_FS_EP_MPS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED-HID_TEST_IFC_DESC_ALL_LEN-7-7+4)
114 
115 
116 static UCHAR device_framework_high_speed[] = {
117 
118     /* Device descriptor */
119     0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
120     0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
121     0x03, 0x01,
122 
123     /* Device qualifier descriptor */
124     0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
125     0x01, 0x00,
126 
127     CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN+HID_TEST_IFC_DESC_ALL_LEN, 2, 1)
128     /* Good HID interface. */
129     HID_MOUSE_IFC_DESC_ALL(0, 0x81)
130     /* Interrupt IN @ 2nd. */
131     HID_TEST_IFC_DESC_ALL(1, 0x03, 3, 0x84, 3)
132 };
133 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed)
134 #define DEVICE_FRAMEWORK_OFFSET_HS_EP_MPS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED-HID_TEST_IFC_DESC_ALL_LEN-7+4)
135 
136 
137     /* String Device Framework :
138      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
139      Byte 2       : Byte containing the index of the descriptor
140      Byte 3       : Byte containing the length of the descriptor string
141     */
142 
143 #define STRING_FRAMEWORK_LENGTH 40
144 static UCHAR string_framework[] = {
145 
146     /* Manufacturer string descriptor : Index 1 */
147         0x09, 0x04, 0x01, 0x0c,
148         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
149         0x6f, 0x67, 0x69, 0x63,
150 
151     /* Product string descriptor : Index 2 */
152         0x09, 0x04, 0x02, 0x0c,
153         0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
154         0x6f, 0x61, 0x72, 0x64,
155 
156     /* Serial Number string descriptor : Index 3 */
157         0x09, 0x04, 0x03, 0x04,
158         0x30, 0x30, 0x30, 0x31
159     };
160 
161 
162     /* Multiple languages are supported on the device, to add
163        a language besides english, the unicode language code must
164        be appended to the language_id_framework array and the length
165        adjusted accordingly. */
166 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
167 static UCHAR language_id_framework[] = {
168 
169     /* English. */
170         0x09, 0x04
171     };
172 
173 
174 UINT  _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
175 
176 
ux_system_host_change_function(ULONG a,UX_HOST_CLASS * b,VOID * c)177 static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c)
178 {
179     return 0;
180 }
181 
instance_activate_callback(VOID * parameter)182 static VOID instance_activate_callback(VOID *parameter)
183 {
184 
185     slave_hid = (UX_SLAVE_CLASS_HID *)parameter;
186 }
187 
error_callback(UINT system_level,UINT system_context,UINT error_code)188 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
189 {
190 
191     // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code);
192 }
193 
194 /* Define what the initial system looks like.  */
195 
196 #ifdef CTEST
test_application_define(void * first_unused_memory)197 void test_application_define(void *first_unused_memory)
198 #else
199 void    usbx_ux_device_class_hid_wMaxPacketSize_test_application_define(void *first_unused_memory)
200 #endif
201 {
202 
203 UINT status;
204 CHAR *                          stack_pointer;
205 CHAR *                          memory_pointer;
206 
207 
208     /* Inform user.  */
209     printf("Running ux_device_class_hid_ wMaxPacketSize tests .................. ");
210     stepinfo("\n");
211 
212     /* Initialize the free memory pointer */
213     stack_pointer = (CHAR *) usbx_memory;
214     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
215 
216     /* Initialize USBX. Memory */
217     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
218 
219     /* Check for error.  */
220     if (status != UX_SUCCESS)
221     {
222 
223         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
224         test_control_return(1);
225     }
226 
227     /* Register the error callback. */
228     _ux_utility_error_callback_register(error_callback);
229 
230     /* The code below is required for installing the host portion of USBX */
231     status =  ux_host_stack_initialize(ux_system_host_change_function);
232     if (status != UX_SUCCESS)
233     {
234 
235         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
236         test_control_return(1);
237     }
238 
239     status =  ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
240     if (status != UX_SUCCESS)
241     {
242 
243         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
244         test_control_return(1);
245     }
246 #if 0
247     /* Register the HID client(s).  */
248     status =  ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry);
249     if (status != UX_SUCCESS)
250     {
251 
252         printf("Error on line %d, error code: %d\n", __LINE__, status);
253         test_control_return(1);
254     }
255 #endif
256     /* The code below is required for installing the device portion of USBX. No call back for
257        device status change in this example. */
258     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
259                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
260                                        string_framework, STRING_FRAMEWORK_LENGTH,
261                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
262     if(status!=UX_SUCCESS)
263     {
264 
265         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
266         test_control_return(1);
267     }
268 
269     /* Initialize the hid class parameters.  */
270     hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor;
271     hid_parameter.ux_device_class_hid_parameter_report_length  = HID_REPORT_LENGTH;
272     hid_parameter.ux_device_class_hid_parameter_callback       = demo_thread_hid_callback;
273     hid_parameter.ux_slave_class_hid_instance_activate         = instance_activate_callback;
274 
275     /* Initialize the device hid class. The class is connected with interface 2 */
276     status  = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
277                                              1, 0, (VOID *)&hid_parameter);
278     if(status!=UX_SUCCESS)
279     {
280 
281         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
282         test_control_return(1);
283     }
284 
285     /* Initialize the simulated device controller.  */
286     status =  _ux_dcd_sim_slave_initialize();
287 
288     /* Check for error.  */
289     if (status != UX_SUCCESS)
290     {
291 
292         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
293         test_control_return(1);
294     }
295 
296     /* Register all the USB host controllers available in this system */
297     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
298 
299     /* Check for error.  */
300     if (status != UX_SUCCESS)
301     {
302 
303         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
304         test_control_return(1);
305     }
306 
307     /* Create the main host simulation thread.  */
308     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
309             stack_pointer, UX_DEMO_STACK_SIZE,
310             20, 20, 1, TX_AUTO_START);
311 
312     /* Check for error.  */
313     if (status != TX_SUCCESS)
314     {
315 
316         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
317         test_control_return(1);
318     }
319 }
320 
_hid_report_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK * callback)321 static VOID  _hid_report_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback)
322 {
323     ULONG length;
324     length = callback->ux_host_class_hid_report_callback_actual_length;
325     if (length > HOST_BUFFER_LENGTH)
326         length = HOST_BUFFER_LENGTH;
327     _ux_utility_memory_copy(host_buffer,
328             callback->ux_host_class_hid_report_callback_buffer,
329             length);
330     host_buffer_length = length;
331 }
332 
tx_demo_thread_host_simulation_entry(ULONG arg)333 static void  tx_demo_thread_host_simulation_entry(ULONG arg)
334 {
335 
336 UINT                                status;
337 UX_DEVICE                           *device;
338 UINT                                i;
339 struct _test {
340     ULONG speed;
341     ULONG wMaxPacketSize;
342 } tests[] = {
343     {UX_FULL_SPEED_DEVICE, 0},
344     {UX_FULL_SPEED_DEVICE, 128},
345     {UX_FULL_SPEED_DEVICE, 8+(2<<11)},
346     {UX_FULL_SPEED_DEVICE, 0xFFFF},
347     {UX_FULL_SPEED_DEVICE, 16},
348     {UX_HIGH_SPEED_DEVICE, 16},
349     {UX_HIGH_SPEED_DEVICE, 16+(1<<11)},
350     {UX_HIGH_SPEED_DEVICE, 0xFFFF},
351     {UX_HIGH_SPEED_DEVICE, 32},
352 };
353 #define N_TESTS (sizeof(tests)/sizeof(struct _test))
354 
355     stepinfo(">>>>>>>>>> Get HID class instance\n");
356 
357     /* Find the HID class */
358     status = demo_class_hid_get();
359     if (status != UX_SUCCESS)
360     {
361 
362         printf("Error on line %d, error code: %d\n", __LINE__, status);
363         test_control_return(1);
364     }
365     if (slave_hid == UX_NULL)
366     {
367         printf("Error on line %d, HID slave instance error\n", __LINE__);
368         test_control_return(1);
369     }
370 
371     /* Get device instance. */
372     status = ux_host_stack_device_get(0, &device);
373     if (status != UX_SUCCESS)
374     {
375         printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status);
376         test_control_return(1);
377     }
378 
379     /* No exit on assert hit.  */
380     ux_test_assert_hit_exit(0);
381 
382     for (i = 0; i < N_TESTS; i ++)
383     {
384 
385         ux_test_dcd_sim_slave_disconnect();
386         ux_test_hcd_sim_host_disconnect();
387 
388         status = demo_class_hid_get();
389 
390         if (tests[i].speed == UX_HIGH_SPEED_DEVICE)
391             _ux_utility_short_put(device_framework_high_speed+DEVICE_FRAMEWORK_OFFSET_HS_EP_MPS, tests[i].wMaxPacketSize);
392         else
393             _ux_utility_short_put(device_framework_full_speed+DEVICE_FRAMEWORK_OFFSET_FS_EP_MPS, tests[i].wMaxPacketSize);
394 
395         ux_test_dcd_sim_slave_connect(tests[i].speed);
396         ux_test_hcd_sim_host_connect(tests[i].speed);
397 
398         /* Find the HID class */
399         status = demo_class_hid_get();
400 
401         /* Set configuration.  */
402         _ux_host_stack_configuration_set(device -> ux_device_first_configuration);
403     }
404 
405     stepinfo(">>>>>>>>>> Test done\n");
406 
407     /* Now disconnect the device.  */
408     _ux_device_stack_disconnect();
409 
410     /* And deinitialize the class.  */
411     status =  ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
412 
413     /* Deinitialize the device side of usbx.  */
414     _ux_device_stack_uninitialize();
415 
416     /* And finally the usbx system resources.  */
417     _ux_system_uninitialize();
418 
419     /* Successful test.  */
420     printf("SUCCESS!\n");
421     test_control_return(0);
422 }
423 
demo_thread_hid_callback(UX_SLAVE_CLASS_HID * class,UX_SLAVE_CLASS_HID_EVENT * event)424 static UINT    demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
425 {
426     return(UX_SUCCESS);
427 }
428