Merge branch vendor/AWK into master.
[dragonfly.git] / tools / tools / usbtest / usb_control_ep_test.c
1 /* $FreeBSD: head/tools/tools/usbtest/usb_control_ep_test.c 254241 2013-08-12 09:15:33Z hselasky $ */
2 /*-
3  * Copyright (c) 2007-2010 Hans Petter Selasky. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <err.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <unistd.h>
34
35 #include <sys/sysctl.h>
36 #include <sys/time.h>
37
38 #include <libusb20.h>
39 #include <libusb20_desc.h>
40
41 #include <bus/u4b/usb_endian.h>
42 #include <bus/u4b/usb.h>
43 #include <bus/u4b/usb_cdc.h>
44
45 #include "usbtest.h"
46
47 static void
48 set_ctrl_ep_fail(int bus, int dev, int ds_fail, int ss_fail)
49 {
50         int error;
51
52         error = sysctlbyname("hw.usb.ctrl_bus_fail", NULL, NULL,
53             &bus, sizeof(bus));
54         if (error != 0)
55                 goto emissing;
56
57         error = sysctlbyname("hw.usb.ctrl_dev_fail", NULL, NULL,
58             &dev, sizeof(dev));
59         if (error != 0)
60                 goto emissing;
61
62         error = sysctlbyname("hw.usb.ctrl_ds_fail", NULL, NULL,
63             &ds_fail, sizeof(ds_fail));
64         if (error != 0)
65                 goto emissing;
66
67         error = sysctlbyname("hw.usb.ctrl_ss_fail", NULL, NULL,
68             &ss_fail, sizeof(ss_fail));
69         if (error != 0)
70                 goto emissing;
71         return;
72
73 emissing:
74         printf("Cannot set USB sysctl, missing USB_REQ_DEBUG option?\n");
75 }
76
77 void
78 usb_control_ep_error_test(uint16_t vid, uint16_t pid)
79 {
80         struct LIBUSB20_CONTROL_SETUP_DECODED req;
81         struct libusb20_device *pdev;
82         uint8_t buffer[256];
83         int error;
84         int fail = 0;
85         int bus;
86         int dev;
87         int cfg;
88
89         pdev = find_usb_device(vid, pid);
90         if (pdev == NULL) {
91                 printf("USB device not found\n");
92                 return;
93         }
94         error = libusb20_dev_open(pdev, 0);
95         if (error) {
96                 printf("Could not open USB device\n");
97                 libusb20_dev_free(pdev);
98                 return;
99         }
100
101         bus = libusb20_dev_get_bus_number(pdev);
102         dev = libusb20_dev_get_address(pdev);
103
104         for (cfg = 0; cfg != 255; cfg++) {
105
106                 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
107                 req.bmRequestType = 0x80; /* read */
108                 req.bRequest = 0x06; /* descriptor */
109                 req.wValue = 0x0200 | cfg; /* config descriptor */
110                 req.wIndex = 0;
111                 req.wLength = 255;
112
113                 printf("Test #%d.1/3 ...\n", cfg);
114
115                 set_ctrl_ep_fail(-1,-1,0,0);
116
117                 error = libusb20_dev_request_sync(pdev, &req, buffer,
118                     NULL, 1000, 0);
119                 if (error != 0) {
120                         printf("Last configuration index is: %d\n", cfg - 1);
121                         break;
122                 }
123
124                 printf("Test #%d.2/3 ...\n", cfg);
125
126                 set_ctrl_ep_fail(bus,dev,1,1);
127
128                 error = libusb20_dev_request_sync(pdev, &req, buffer,
129                     NULL, 1000, 0);
130
131                 set_ctrl_ep_fail(-1,-1,0,0);
132
133                 error = libusb20_dev_request_sync(pdev, &req, buffer,
134                     NULL, 1000, 0);
135                 if (error != 0) {
136                         printf("Cannot fetch descriptor (unexpected)\n");
137                         fail++;
138                 }
139
140                 printf("Test #%d.3/3 ...\n", cfg);
141
142                 set_ctrl_ep_fail(bus,dev,0,1);
143
144                 error = libusb20_dev_request_sync(pdev, &req, buffer,
145                     NULL, 1000, 0);
146
147                 set_ctrl_ep_fail(-1,-1,0,0);
148
149                 error = libusb20_dev_request_sync(pdev, &req, buffer,
150                     NULL, 1000, 0);
151                 if (error != 0) {
152                         printf("Cannot fetch descriptor (unexpected)\n");
153                         fail++;
154                 }
155         }
156
157         libusb20_dev_close(pdev);
158         libusb20_dev_free(pdev);
159
160         printf("Test completed detecting %d failures\nDone\n\n", fail);
161 }
162
163 void
164 usb_get_string_desc_test(uint16_t vid, uint16_t pid)
165 {
166         struct libusb20_device *pdev;
167         uint32_t x;
168         uint32_t y;
169         uint32_t valid;
170         uint8_t *buf;
171         int error;
172
173         pdev = find_usb_device(vid, pid);
174         if (pdev == NULL) {
175                 printf("USB device not found\n");
176                 return;
177         }
178         error = libusb20_dev_open(pdev, 0);
179         if (error) {
180                 printf("Could not open USB device\n");
181                 libusb20_dev_free(pdev);
182                 return;
183         }
184         buf = malloc(256);
185         if (buf == NULL) {
186                 printf("Cannot allocate memory\n");
187                 libusb20_dev_free(pdev);
188                 return;
189         }
190         valid = 0;
191
192         printf("Starting string descriptor test for "
193             "VID=0x%04x PID=0x%04x\n", vid, pid);
194
195         for (x = 0; x != 256; x++) {
196
197                 if (libusb20_dev_check_connected(pdev) != 0) {
198                         printf("Device disconnected\n");
199                         break;
200                 }
201                 printf("%d .. ", (int)x);
202
203                 fflush(stdout);
204
205                 error = libusb20_dev_req_string_simple_sync(pdev, x, buf, 255);
206
207                 if (error == 0) {
208                         printf("\nINDEX=%d, STRING='%s' (Default language)\n", (int)x, buf);
209                         fflush(stdout);
210                 } else {
211                         continue;
212                 }
213
214                 valid = 0;
215
216                 for (y = 0; y != 65536; y++) {
217
218                         if (libusb20_dev_check_connected(pdev) != 0) {
219                                 printf("Device disconnected\n");
220                                 break;
221                         }
222                         error = libusb20_dev_req_string_sync(pdev, x, y, buf, 256);
223                         if (error == 0)
224                                 valid++;
225                 }
226
227                 printf("String at INDEX=%d responds to %d "
228                     "languages\n", (int)x, (int)valid);
229         }
230
231         printf("\nDone\n");
232
233         free(buf);
234
235         libusb20_dev_free(pdev);
236 }
237
238 void
239 usb_port_reset_test(uint16_t vid, uint16_t pid, uint32_t duration)
240 {
241         struct timeval sub_tv;
242         struct timeval ref_tv;
243         struct timeval res_tv;
244
245         struct libusb20_device *pdev;
246
247         int error;
248         int iter;
249         int errcnt;
250
251         time_t last_sec;
252
253         /* sysctl() - no set config */
254
255         pdev = find_usb_device(vid, pid);
256         if (pdev == NULL) {
257                 printf("USB device not found\n");
258                 return;
259         }
260         error = libusb20_dev_open(pdev, 0);
261         if (error) {
262                 libusb20_dev_free(pdev);
263                 printf("Could not open USB device\n");
264                 return;
265         }
266         iter = 0;
267
268         errcnt = 0;
269
270         gettimeofday(&ref_tv, 0);
271
272         last_sec = ref_tv.tv_sec;
273
274         while (1) {
275
276                 gettimeofday(&sub_tv, 0);
277
278                 if (last_sec != sub_tv.tv_sec) {
279
280                         printf("STATUS: ID=%u, ERR=%u\n",
281                             (int)iter, (int)errcnt);
282
283                         fflush(stdout);
284
285                         last_sec = sub_tv.tv_sec;
286                 }
287                 timersub(&sub_tv, &ref_tv, &res_tv);
288
289                 if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
290                         break;
291
292                 if (libusb20_dev_reset(pdev)) {
293                         errcnt++;
294                         usleep(50000);
295                 }
296                 if (libusb20_dev_check_connected(pdev) != 0) {
297                         printf("Device disconnected\n");
298                         break;
299                 }
300                 iter++;
301         }
302
303         libusb20_dev_reset(pdev);
304
305         libusb20_dev_free(pdev);
306 }
307
308 void
309 usb_set_config_test(uint16_t vid, uint16_t pid, uint32_t duration)
310 {
311         struct libusb20_device *pdev;
312         struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
313         int x;
314         int error;
315         int failed;
316         int exp;
317
318         pdev = find_usb_device(vid, pid);
319         if (pdev == NULL) {
320                 printf("USB device not found\n");
321                 return;
322         }
323         error = libusb20_dev_open(pdev, 0);
324         if (error) {
325                 printf("Could not open USB device\n");
326                 libusb20_dev_free(pdev);
327                 return;
328         }
329         failed = 0;
330
331         printf("Starting set config test for "
332             "VID=0x%04x PID=0x%04x\n", vid, pid);
333
334         for (x = 255; x > -1; x--) {
335
336                 error = libusb20_dev_set_config_index(pdev, x);
337                 if (error == 0) {
338                         if (x == 255) {
339                                 printf("Unconfiguring USB device "
340                                     "was successful\n");
341                         } else {
342                                 printf("Setting configuration %d "
343                                     "was successful\n", x);
344                         }
345                 } else {
346                         failed++;
347                 }
348         }
349
350         ddesc = libusb20_dev_get_device_desc(pdev);
351         if (ddesc != NULL)
352                 exp = ddesc->bNumConfigurations + 1;
353         else
354                 exp = 1;
355
356         printf("\n\n"
357             "Set configuration summary\n"
358             "Valid count:  %d/%d %s\n"
359             "Failed count: %d\n",
360             256 - failed, exp,
361             (exp == (256 - failed)) ? "(expected)" : "(unexpected)",
362             failed);
363
364         libusb20_dev_free(pdev);
365 }
366
367 void
368 usb_get_descriptor_test(uint16_t vid, uint16_t pid, uint32_t duration)
369 {
370         struct libusb20_device *pdev;
371
372         pdev = find_usb_device(vid, pid);
373         if (pdev == NULL) {
374                 printf("USB device not found\n");
375                 return;
376         }
377         libusb20_dev_free(pdev);
378 }
379
380 void
381 usb_suspend_resume_test(uint16_t vid, uint16_t pid, uint32_t duration)
382 {
383         struct timeval sub_tv;
384         struct timeval ref_tv;
385         struct timeval res_tv;
386
387         struct libusb20_device *pdev;
388
389         time_t last_sec;
390
391         int iter;
392         int error;
393         int ptimo;
394         int errcnt;
395         int power_old;
396
397         ptimo = 1;                      /* second(s) */
398
399         error = sysctlbyname("hw.usb.power_timeout", NULL, NULL,
400             &ptimo, sizeof(ptimo));
401
402         if (error != 0) {
403                 printf("WARNING: Could not set power "
404                     "timeout to 1 (error=%d) \n", errno);
405         }
406         pdev = find_usb_device(vid, pid);
407         if (pdev == NULL) {
408                 printf("USB device not found\n");
409                 return;
410         }
411         error = libusb20_dev_open(pdev, 0);
412         if (error) {
413                 printf("Could not open USB device\n");
414                 libusb20_dev_free(pdev);
415                 return;
416         }
417         power_old = libusb20_dev_get_power_mode(pdev);
418
419         printf("Starting suspend and resume "
420             "test for VID=0x%04x PID=0x%04x\n", vid, pid);
421
422         iter = 0;
423         errcnt = 0;
424
425         gettimeofday(&ref_tv, 0);
426
427         last_sec = ref_tv.tv_sec;
428
429         while (1) {
430
431                 if (libusb20_dev_check_connected(pdev) != 0) {
432                         printf("Device disconnected\n");
433                         break;
434                 }
435                 gettimeofday(&sub_tv, 0);
436
437                 if (last_sec != sub_tv.tv_sec) {
438
439                         printf("STATUS: ID=%u, ERR=%u\n",
440                             (int)iter, (int)errcnt);
441
442                         fflush(stdout);
443
444                         last_sec = sub_tv.tv_sec;
445                 }
446                 timersub(&sub_tv, &ref_tv, &res_tv);
447
448                 if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration))
449                         break;
450
451                 error = libusb20_dev_set_power_mode(pdev, (iter & 1) ?
452                     LIBUSB20_POWER_ON : LIBUSB20_POWER_SAVE);
453
454                 if (error)
455                         errcnt++;
456
457                 /* wait before switching power mode */
458                 usleep(4100000 +
459                     (((uint32_t)usb_ts_rand_noise()) % 2000000U));
460
461                 iter++;
462         }
463
464         /* restore default power mode */
465         libusb20_dev_set_power_mode(pdev, power_old);
466
467         libusb20_dev_free(pdev);
468 }
469
470 void
471 usb_set_and_clear_stall_test(uint16_t vid, uint16_t pid)
472 {
473         struct libusb20_device *pdev;
474         struct libusb20_transfer *pxfer;
475
476         int iter;
477         int error;
478         int errcnt;
479         int ep;
480
481         pdev = find_usb_device(vid, pid);
482         if (pdev == NULL) {
483                 printf("USB device not found\n");
484                 return;
485         }
486         error = libusb20_dev_open(pdev, 1);
487         if (error) {
488                 printf("Could not open USB device\n");
489                 libusb20_dev_free(pdev);
490                 return;
491         }
492         printf("Starting set and clear stall test "
493             "for VID=0x%04x PID=0x%04x\n", vid, pid);
494
495         iter = 0;
496         errcnt = 0;
497
498         for (ep = 2; ep != 32; ep++) {
499
500                 struct LIBUSB20_CONTROL_SETUP_DECODED setup_set_stall;
501                 struct LIBUSB20_CONTROL_SETUP_DECODED setup_get_status;
502
503                 uint8_t epno = ((ep / 2) | ((ep & 1) << 7));
504                 uint8_t buf[1];
505
506                 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_set_stall);
507                 setup_set_stall.bmRequestType = 0x02;   /* write endpoint */
508                 setup_set_stall.bRequest = 0x03;        /* set feature */
509                 setup_set_stall.wValue = 0x00;  /* UF_ENDPOINT_HALT */
510                 setup_set_stall.wIndex = epno;
511                 setup_set_stall.wLength = 0;
512
513                 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup_get_status);
514                 setup_get_status.bmRequestType = 0x82;  /* read endpoint */
515                 setup_get_status.bRequest = 0x00;       /* get status */
516                 setup_get_status.wValue = 0x00;
517                 setup_get_status.wIndex = epno;
518                 setup_get_status.wLength = 1;
519
520                 if (libusb20_dev_check_connected(pdev) != 0) {
521                         printf("Device disconnected\n");
522                         break;
523                 }
524                 pxfer = libusb20_tr_get_pointer(pdev, 0);
525
526                 error = libusb20_tr_open(pxfer, 1, 1, epno);
527
528                 if (error != 0) {
529                         printf("Endpoint 0x%02x does not exist "
530                             "in current setting. (%s, ignored)\n",
531                             epno, libusb20_strerror(error));
532                         continue;
533                 }
534                 printf("Stalling endpoint 0x%02x\n", epno);
535
536                 /* set stall */
537                 error = libusb20_dev_request_sync(pdev,
538                     &setup_set_stall, NULL, NULL, 250, 0);
539
540                 if (error != 0) {
541                         printf("Endpoint 0x%02x does not allow "
542                             "setting of stall. (%s)\n",
543                             epno, libusb20_strerror(error));
544                         errcnt++;
545                 }
546                 /* get EP status */
547                 buf[0] = 0;
548                 error = libusb20_dev_request_sync(pdev,
549                     &setup_get_status, buf, NULL, 250, 0);
550
551                 if (error != 0) {
552                         printf("Endpoint 0x%02x does not allow "
553                             "reading status. (%s)\n",
554                             epno, libusb20_strerror(error));
555                         errcnt++;
556                 } else {
557                         if (!(buf[0] & 1)) {
558                                 printf("Endpoint 0x%02x status is "
559                                     "not set to stalled\n", epno);
560                                 errcnt++;
561                         }
562                 }
563
564                 buf[0] = 0;
565                 error = libusb20_tr_bulk_intr_sync(pxfer, buf, 1, NULL, 250);
566                 if (error != LIBUSB20_TRANSFER_STALL) {
567                         printf("Endpoint 0x%02x does not appear to "
568                             "have stalled. Missing stall PID!\n", epno);
569                         errcnt++;
570                 }
571                 printf("Unstalling endpoint 0x%02x\n", epno);
572
573                 libusb20_tr_clear_stall_sync(pxfer);
574
575                 /* get EP status */
576                 buf[0] = 0;
577                 error = libusb20_dev_request_sync(pdev,
578                     &setup_get_status, buf, NULL, 250, 0);
579
580                 if (error != 0) {
581                         printf("Endpoint 0x%02x does not allow "
582                             "reading status. (%s)\n",
583                             epno, libusb20_strerror(error));
584                         errcnt++;
585                 } else {
586                         if (buf[0] & 1) {
587                                 printf("Endpoint 0x%02x status is "
588                                     "still stalled\n", epno);
589                                 errcnt++;
590                         }
591                 }
592
593                 libusb20_tr_close(pxfer);
594                 iter++;
595         }
596
597         libusb20_dev_free(pdev);
598
599         printf("\n"
600             "Test summary\n"
601             "============\n"
602             "Endpoints tested: %d\n"
603             "Errors: %d\n", iter, errcnt);
604 }
605
606 void
607 usb_set_alt_interface_test(uint16_t vid, uint16_t pid)
608 {
609         struct libusb20_device *pdev;
610         struct libusb20_config *config;
611
612         int iter;
613         int error;
614         int errcnt;
615         int n;
616         int m;
617
618         pdev = find_usb_device(vid, pid);
619         if (pdev == NULL) {
620                 printf("USB device not found\n");
621                 return;
622         }
623         printf("Starting set alternate setting test "
624             "for VID=0x%04x PID=0x%04x\n", vid, pid);
625
626         config = libusb20_dev_alloc_config(pdev,
627             libusb20_dev_get_config_index(pdev));
628         if (config == NULL) {
629                 printf("Could not get configuration descriptor\n");
630                 libusb20_dev_free(pdev);
631                 return;
632         }
633         iter = 0;
634         errcnt = 0;
635
636         for (n = 0; n != config->num_interface; n++) {
637                 /* detach kernel driver */
638                 libusb20_dev_detach_kernel_driver(pdev, n);
639
640                 error = libusb20_dev_open(pdev, 0);
641                 if (error)
642                         printf("ERROR could not open device\n");
643
644                 /* Try the alternate settings */
645                 for (m = 0; m != config->interface[n].num_altsetting; m++) {
646
647                         iter++;
648
649                         if (libusb20_dev_set_alt_index(pdev, n, m + 1)) {
650                                 printf("ERROR on interface %d alt %d\n", n, m + 1);
651                                 errcnt++;
652                         }
653                 }
654
655                 /* Restore to default */
656
657                 iter++;
658
659                 if (libusb20_dev_set_alt_index(pdev, n, 0)) {
660                         printf("ERROR on interface %d alt %d\n", n, 0);
661                         errcnt++;
662                 }
663                 libusb20_dev_close(pdev);
664         }
665
666         libusb20_dev_free(pdev);
667
668         printf("\n"
669             "Test summary\n"
670             "============\n"
671             "Interfaces tested: %d\n"
672             "Errors: %d\n", iter, errcnt);
673 }