]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - usr.sbin/usbconfig/usbconfig.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / usr.sbin / usbconfig / usbconfig.c
1 /* $FreeBSD$ */
2 /*-
3  * Copyright (c) 2008 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 <stdlib.h>
29 #include <stdint.h>
30 #include <err.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <errno.h>
35 #include <ctype.h>
36
37 #include <libusb20_desc.h>
38 #include <libusb20.h>
39
40 #include "dump.h"
41
42 struct options {
43         const char *quirkname;
44         void   *buffer;
45         int template;
46         gid_t   gid;
47         uid_t   uid;
48         mode_t  mode;
49         uint32_t got_any;
50         struct LIBUSB20_CONTROL_SETUP_DECODED setup;
51         uint16_t bus;
52         uint16_t addr;
53         uint16_t iface;
54         uint16_t vid;
55         uint16_t pid;
56         uint16_t lo_rev;                /* inclusive */
57         uint16_t hi_rev;                /* inclusive */
58         uint8_t string_index;
59         uint8_t config_index;
60         uint8_t alt_index;
61         uint8_t got_list:1;
62         uint8_t got_bus:1;
63         uint8_t got_addr:1;
64         uint8_t got_iface:1;
65         uint8_t got_set_config:1;
66         uint8_t got_set_alt:1;
67         uint8_t got_set_template:1;
68         uint8_t got_get_template:1;
69         uint8_t got_suspend:1;
70         uint8_t got_resume:1;
71         uint8_t got_reset:1;
72         uint8_t got_power_off:1;
73         uint8_t got_power_save:1;
74         uint8_t got_power_on:1;
75         uint8_t got_dump_device_quirks:1;
76         uint8_t got_dump_quirk_names:1;
77         uint8_t got_dump_device_desc:1;
78         uint8_t got_dump_curr_config:1;
79         uint8_t got_dump_all_config:1;
80         uint8_t got_dump_info:1;
81         uint8_t got_show_iface_driver:1;
82         uint8_t got_remove_device_quirk:1;
83         uint8_t got_add_device_quirk:1;
84         uint8_t got_dump_string:1;
85         uint8_t got_do_request:1;
86 };
87
88 struct token {
89         const char *name;
90         uint8_t value;
91         uint8_t narg;
92 };
93
94 enum {
95         T_UNIT,
96         T_ADDR,
97         T_IFACE,
98         T_SET_CONFIG,
99         T_SET_ALT,
100         T_SET_TEMPLATE,
101         T_GET_TEMPLATE,
102         T_ADD_DEVICE_QUIRK,
103         T_REMOVE_DEVICE_QUIRK,
104         T_SHOW_IFACE_DRIVER,
105         T_DUMP_QUIRK_NAMES,
106         T_DUMP_DEVICE_QUIRKS,
107         T_DUMP_DEVICE_DESC,
108         T_DUMP_CURR_CONFIG_DESC,
109         T_DUMP_ALL_CONFIG_DESC,
110         T_DUMP_STRING,
111         T_DUMP_INFO,
112         T_SUSPEND,
113         T_RESUME,
114         T_POWER_OFF,
115         T_POWER_SAVE,
116         T_POWER_ON,
117         T_RESET,
118         T_LIST,
119         T_DO_REQUEST,
120 };
121
122 static struct options options;
123
124 static const struct token token[] = {
125         {"-u", T_UNIT, 1},
126         {"-a", T_ADDR, 1},
127         {"-i", T_IFACE, 1},
128         {"set_config", T_SET_CONFIG, 1},
129         {"set_alt", T_SET_ALT, 1},
130         {"set_template", T_SET_TEMPLATE, 1},
131         {"get_template", T_GET_TEMPLATE, 0},
132         {"add_dev_quirk_vplh", T_ADD_DEVICE_QUIRK, 5},
133         {"remove_dev_quirk_vplh", T_REMOVE_DEVICE_QUIRK, 5},
134         {"dump_quirk_names", T_DUMP_QUIRK_NAMES, 0},
135         {"dump_device_quirks", T_DUMP_DEVICE_QUIRKS, 0},
136         {"dump_device_desc", T_DUMP_DEVICE_DESC, 0},
137         {"dump_curr_config_desc", T_DUMP_CURR_CONFIG_DESC, 0},
138         {"dump_all_config_desc", T_DUMP_ALL_CONFIG_DESC, 0},
139         {"dump_string", T_DUMP_STRING, 1},
140         {"dump_info", T_DUMP_INFO, 0},
141         {"show_ifdrv", T_SHOW_IFACE_DRIVER, 0},
142         {"suspend", T_SUSPEND, 0},
143         {"resume", T_RESUME, 0},
144         {"power_off", T_POWER_OFF, 0},
145         {"power_save", T_POWER_SAVE, 0},
146         {"power_on", T_POWER_ON, 0},
147         {"reset", T_RESET, 0},
148         {"list", T_LIST, 0},
149         {"do_request", T_DO_REQUEST, 5},
150 };
151
152 static void
153 be_dev_remove_quirk(struct libusb20_backend *pbe,
154     uint16_t vid, uint16_t pid, uint16_t lorev, uint16_t hirev,
155     const char *str)
156 {
157         struct libusb20_quirk q;
158         int error;
159
160         memset(&q, 0, sizeof(q));
161
162         q.vid = vid;
163         q.pid = pid;
164         q.bcdDeviceLow = lorev;
165         q.bcdDeviceHigh = hirev;
166         strlcpy(q.quirkname, str, sizeof(q.quirkname));
167
168         error = libusb20_be_remove_dev_quirk(pbe, &q);
169         if (error) {
170                 printf("Removing quirk '%s' failed, continuing.\n", str);
171         }
172         return;
173 }
174
175 static void
176 be_dev_add_quirk(struct libusb20_backend *pbe,
177     uint16_t vid, uint16_t pid, uint16_t lorev, uint16_t hirev,
178     const char *str)
179 {
180         struct libusb20_quirk q;
181         int error;
182
183         memset(&q, 0, sizeof(q));
184
185         q.vid = vid;
186         q.pid = pid;
187         q.bcdDeviceLow = lorev;
188         q.bcdDeviceHigh = hirev;
189         strlcpy(q.quirkname, str, sizeof(q.quirkname));
190
191         error = libusb20_be_add_dev_quirk(pbe, &q);
192         if (error) {
193                 printf("Adding quirk '%s' failed, continuing.\n", str);
194         }
195         return;
196 }
197
198 static uint8_t
199 get_token(const char *str, uint8_t narg)
200 {
201         uint8_t n;
202
203         for (n = 0; n != (sizeof(token) / sizeof(token[0])); n++) {
204                 if (strcasecmp(str, token[n].name) == 0) {
205                         if (token[n].narg > narg) {
206                                 /* too few arguments */
207                                 break;
208                         }
209                         return (token[n].value);
210                 }
211         }
212         return (0 - 1);
213 }
214
215 static uid_t
216 num_id(const char *name, const char *type)
217 {
218         uid_t val;
219         char *ep;
220
221         errno = 0;
222         val = strtoul(name, &ep, 0);
223         if (errno) {
224                 err(1, "%s", name);
225         }
226         if (*ep != '\0') {
227                 errx(1, "%s: illegal %s name", name, type);
228         }
229         return (val);
230 }
231
232 static int
233 get_int(const char *s)
234 {
235         int val;
236         char *ep;
237
238         errno = 0;
239         val = strtoul(s, &ep, 0);
240         if (errno) {
241                 err(1, "%s", s);
242         }
243         if (*ep != '\0') {
244                 errx(1, "illegal number: %s", s);
245         }
246         return val;
247 }
248
249 static void
250 usage(void)
251 {
252         printf(""
253             "usbconfig - configure the USB subsystem" "\n"
254             "usage: usbconfig -u <busnum> -a <devaddr> -i <ifaceindex> [cmds...]" "\n"
255             "commands:" "\n"
256             "  set_config <cfg_index>" "\n"
257             "  set_alt <alt_index>" "\n"
258             "  set_template <template>" "\n"
259             "  get_template" "\n"
260             "  add_dev_quirk_vplh <vid> <pid> <lo_rev> <hi_rev> <quirk>" "\n"
261             "  remove_dev_quirk_vplh <vid> <pid> <lo_rev> <hi_rev> <quirk>" "\n"
262             "  dump_quirk_names" "\n"
263             "  dump_device_quirks" "\n"
264             "  dump_device_desc" "\n"
265             "  dump_curr_config_desc" "\n"
266             "  dump_all_config_desc" "\n"
267             "  dump_string <index>" "\n"
268             "  dump_info" "\n"
269             "  show_ifdrv" "\n"
270             "  suspend" "\n"
271             "  resume" "\n"
272             "  power_off" "\n"
273             "  power_save" "\n"
274             "  power_on" "\n"
275             "  reset" "\n"
276             "  list" "\n"
277             "  do_request <bmReqTyp> <bReq> <wVal> <wIdx> <wLen> <data...>" "\n"
278         );
279         exit(1);
280 }
281
282 static void
283 reset_options(struct options *opt)
284 {
285         if (opt->buffer)
286                 free(opt->buffer);
287         memset(opt, 0, sizeof(*opt));
288         return;
289 }
290
291 static void
292 flush_command(struct libusb20_backend *pbe, struct options *opt)
293 {
294         struct libusb20_device *pdev = NULL;
295         uint32_t matches = 0;
296         uint8_t dump_any;
297
298         /* check for invalid option combinations */
299         if ((opt->got_suspend +
300             opt->got_resume +
301             opt->got_reset +
302             opt->got_set_config +
303             opt->got_set_alt +
304             opt->got_power_save +
305             opt->got_power_on +
306             opt->got_power_off) > 1) {
307                 err(1, "can only specify one of 'set_config', "
308                     "'set_alt', 'reset', 'suspend', 'resume', "
309                     "'power_save', 'power_on' and 'power_off' "
310                     "at the same time!");
311         }
312         if (opt->got_dump_quirk_names) {
313                 opt->got_any--;
314                 dump_be_quirk_names(pbe);
315         }
316         if (opt->got_dump_device_quirks) {
317                 opt->got_any--;
318                 dump_be_dev_quirks(pbe);
319         }
320         if (opt->got_remove_device_quirk) {
321                 opt->got_any--;
322                 be_dev_remove_quirk(pbe,
323                     opt->vid, opt->pid, opt->lo_rev, opt->hi_rev, opt->quirkname);
324         }
325         if (opt->got_add_device_quirk) {
326                 opt->got_any--;
327                 be_dev_add_quirk(pbe,
328                     opt->vid, opt->pid, opt->lo_rev, opt->hi_rev, opt->quirkname);
329         }
330         if (opt->got_set_template) {
331                 opt->got_any--;
332                 if (libusb20_be_set_template(pbe, opt->template)) {
333                         printf("Setting USB template %u failed, "
334                             "continuing.\n", opt->template);
335                 }
336         }
337         if (opt->got_get_template) {
338                 opt->got_any--;
339                 if (libusb20_be_get_template(pbe, &opt->template))
340                         printf("USB template: <unknown>\n");
341                 else
342                         printf("USB template: %u\n", opt->template);
343         }
344         if (opt->got_any == 0) {
345                 /*
346                  * do not scan through all the devices if there are no valid
347                  * options
348                  */
349                 goto done;
350         }
351         while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
352
353                 if (opt->got_bus &&
354                     (libusb20_dev_get_bus_number(pdev) != opt->bus)) {
355                         continue;
356                 }
357                 if (opt->got_addr &&
358                     (libusb20_dev_get_address(pdev) != opt->addr)) {
359                         continue;
360                 }
361                 matches++;
362
363                 if (libusb20_dev_open(pdev, 0)) {
364                         err(1, "could not open device");
365                 }
366                 if (opt->got_dump_string) {
367                         char *pbuf;
368
369                         pbuf = malloc(256);
370                         if (pbuf == NULL) {
371                                 err(1, "out of memory");
372                         }
373                         if (libusb20_dev_req_string_simple_sync(pdev,
374                             opt->string_index, pbuf, 256)) {
375                                 printf("STRING_0x%02x = <read error>\n",
376                                     opt->string_index);
377                         } else {
378                                 printf("STRING_0x%02x = <%s>\n",
379                                     opt->string_index, pbuf);
380                         }
381                         free(pbuf);
382                 }
383                 if (opt->got_do_request) {
384                         uint16_t actlen;
385                         uint16_t t;
386
387                         if (libusb20_dev_request_sync(pdev, &opt->setup,
388                             opt->buffer, &actlen, 5000 /* 5 seconds */ , 0)) {
389                                 printf("REQUEST = <ERROR>\n");
390                         } else if (!(opt->setup.bmRequestType &
391                             LIBUSB20_ENDPOINT_IN)) {
392                                 printf("REQUEST = <OK>\n");
393                         } else {
394                                 t = actlen;
395                                 printf("REQUEST = <");
396                                 for (t = 0; t != actlen; t++) {
397                                         printf("0x%02x%s",
398                                             ((uint8_t *)opt->buffer)[t],
399                                             (t == (actlen - 1)) ? "" : " ");
400                                 }
401                                 printf("><");
402                                 for (t = 0; t != actlen; t++) {
403                                         char c;
404
405                                         c = ((uint8_t *)opt->buffer)[t];
406                                         if ((c != '<') &&
407                                             (c != '>') && isprint(c)) {
408                                                 putchar(c);
409                                         }
410                                 }
411                                 printf(">\n");
412                         }
413                 }
414                 if (opt->got_set_config) {
415                         if (libusb20_dev_set_config_index(pdev,
416                             opt->config_index)) {
417                                 err(1, "could not set config index");
418                         }
419                 }
420                 if (opt->got_set_alt) {
421                         if (libusb20_dev_set_alt_index(pdev, opt->iface,
422                             opt->alt_index)) {
423                                 err(1, "could not set alternate setting");
424                         }
425                 }
426                 if (opt->got_reset) {
427                         if (libusb20_dev_reset(pdev)) {
428                                 err(1, "could not reset device");
429                         }
430                 }
431                 if (opt->got_suspend) {
432                         if (libusb20_dev_set_power_mode(pdev,
433                             LIBUSB20_POWER_SUSPEND)) {
434                                 err(1, "could not set suspend");
435                         }
436                 }
437                 if (opt->got_resume) {
438                         if (libusb20_dev_set_power_mode(pdev,
439                             LIBUSB20_POWER_RESUME)) {
440                                 err(1, "could not set resume");
441                         }
442                 }
443                 if (opt->got_power_off) {
444                         if (libusb20_dev_set_power_mode(pdev,
445                             LIBUSB20_POWER_OFF)) {
446                                 err(1, "could not set power OFF");
447                         }
448                 }
449                 if (opt->got_power_save) {
450                         if (libusb20_dev_set_power_mode(pdev,
451                             LIBUSB20_POWER_SAVE)) {
452                                 err(1, "could not set power SAVE");
453                         }
454                 }
455                 if (opt->got_power_on) {
456                         if (libusb20_dev_set_power_mode(pdev,
457                             LIBUSB20_POWER_ON)) {
458                                 err(1, "could not set power ON");
459                         }
460                 }
461                 dump_any =
462                     (opt->got_dump_device_desc ||
463                     opt->got_dump_curr_config ||
464                     opt->got_dump_all_config ||
465                     opt->got_dump_info);
466
467                 if (opt->got_list || dump_any) {
468                         dump_device_info(pdev,
469                             opt->got_show_iface_driver);
470                 }
471                 if (opt->got_dump_device_desc) {
472                         printf("\n");
473                         dump_device_desc(pdev);
474                 }
475                 if (opt->got_dump_all_config) {
476                         printf("\n");
477                         dump_config(pdev, 1);
478                 } else if (opt->got_dump_curr_config) {
479                         printf("\n");
480                         dump_config(pdev, 0);
481                 }
482                 if (dump_any) {
483                         printf("\n");
484                 }
485                 if (libusb20_dev_close(pdev)) {
486                         err(1, "could not close device");
487                 }
488         }
489
490         if (matches == 0) {
491                 printf("No device match or lack of permissions.\n");
492         }
493 done:
494         reset_options(opt);
495
496         return;
497 }
498
499 int
500 main(int argc, char **argv)
501 {
502         struct libusb20_backend *pbe;
503         struct options *opt = &options;
504         int n;
505         int t;
506
507         if (argc < 1) {
508                 usage();
509         }
510         pbe = libusb20_be_alloc_default();
511         if (pbe == NULL)
512                 err(1, "could not access USB backend\n");
513
514         for (n = 1; n != argc; n++) {
515
516                 /* get number of additional options */
517                 t = (argc - n - 1);
518                 if (t > 255)
519                         t = 255;
520                 switch (get_token(argv[n], t)) {
521                 case T_ADD_DEVICE_QUIRK:
522                         if (opt->got_add_device_quirk) {
523                                 flush_command(pbe, opt);
524                         }
525                         opt->vid = num_id(argv[n + 1], "Vendor ID");
526                         opt->pid = num_id(argv[n + 2], "Product ID");
527                         opt->lo_rev = num_id(argv[n + 3], "Low Revision");
528                         opt->hi_rev = num_id(argv[n + 4], "High Revision");
529                         opt->quirkname = argv[n + 5];
530                         n += 5;
531
532                         opt->got_add_device_quirk = 1;
533                         opt->got_any++;
534                         break;
535
536                 case T_REMOVE_DEVICE_QUIRK:
537                         if (opt->got_remove_device_quirk) {
538                                 flush_command(pbe, opt);
539                         }
540                         opt->vid = num_id(argv[n + 1], "Vendor ID");
541                         opt->pid = num_id(argv[n + 2], "Product ID");
542                         opt->lo_rev = num_id(argv[n + 3], "Low Revision");
543                         opt->hi_rev = num_id(argv[n + 4], "High Revision");
544                         opt->quirkname = argv[n + 5];
545                         n += 5;
546                         opt->got_remove_device_quirk = 1;
547                         opt->got_any++;
548                         break;
549
550                 case T_DUMP_QUIRK_NAMES:
551                         opt->got_dump_quirk_names = 1;
552                         opt->got_any++;
553                         break;
554
555                 case T_DUMP_DEVICE_QUIRKS:
556                         opt->got_dump_device_quirks = 1;
557                         opt->got_any++;
558                         break;
559
560                 case T_SHOW_IFACE_DRIVER:
561                         opt->got_show_iface_driver = 1;
562                         break;
563
564                 case T_UNIT:
565                         if (opt->got_any) {
566                                 /* allow multiple commands on the same line */
567                                 flush_command(pbe, opt);
568                         }
569                         opt->bus = num_id(argv[n + 1], "busnum");
570                         opt->got_bus = 1;
571                         n++;
572                         break;
573                 case T_ADDR:
574                         opt->addr = num_id(argv[n + 1], "addr");
575                         opt->got_addr = 1;
576                         n++;
577                         break;
578                 case T_IFACE:
579                         opt->iface = num_id(argv[n + 1], "iface");
580                         opt->got_iface = 1;
581                         n++;
582                         break;
583                 case T_SET_CONFIG:
584                         opt->config_index = num_id(argv[n + 1], "cfg_index");
585                         opt->got_set_config = 1;
586                         opt->got_any++;
587                         n++;
588                         break;
589                 case T_SET_ALT:
590                         opt->alt_index = num_id(argv[n + 1], "cfg_index");
591                         opt->got_set_alt = 1;
592                         opt->got_any++;
593                         n++;
594                         break;
595                 case T_SET_TEMPLATE:
596                         opt->template = get_int(argv[n + 1]);
597                         opt->got_set_template = 1;
598                         opt->got_any++;
599                         n++;
600                         break;
601                 case T_GET_TEMPLATE:
602                         opt->got_get_template = 1;
603                         opt->got_any++;
604                         break;
605                 case T_DUMP_DEVICE_DESC:
606                         opt->got_dump_device_desc = 1;
607                         opt->got_any++;
608                         break;
609                 case T_DUMP_CURR_CONFIG_DESC:
610                         opt->got_dump_curr_config = 1;
611                         opt->got_any++;
612                         break;
613                 case T_DUMP_ALL_CONFIG_DESC:
614                         opt->got_dump_all_config = 1;
615                         opt->got_any++;
616                         break;
617                 case T_DUMP_INFO:
618                         opt->got_dump_info = 1;
619                         opt->got_any++;
620                         break;
621                 case T_DUMP_STRING:
622                         if (opt->got_dump_string) {
623                                 flush_command(pbe, opt);
624                         }
625                         opt->string_index = num_id(argv[n + 1], "str_index");
626                         opt->got_dump_string = 1;
627                         opt->got_any++;
628                         n++;
629                         break;
630                 case T_SUSPEND:
631                         opt->got_suspend = 1;
632                         opt->got_any++;
633                         break;
634                 case T_RESUME:
635                         opt->got_resume = 1;
636                         opt->got_any++;
637                         break;
638                 case T_POWER_OFF:
639                         opt->got_power_off = 1;
640                         opt->got_any++;
641                         break;
642                 case T_POWER_SAVE:
643                         opt->got_power_save = 1;
644                         opt->got_any++;
645                         break;
646                 case T_POWER_ON:
647                         opt->got_power_on = 1;
648                         opt->got_any++;
649                         break;
650                 case T_RESET:
651                         opt->got_reset = 1;
652                         opt->got_any++;
653                         break;
654                 case T_LIST:
655                         opt->got_list = 1;
656                         opt->got_any++;
657                         break;
658                 case T_DO_REQUEST:
659                         if (opt->got_do_request) {
660                                 flush_command(pbe, opt);
661                         }
662                         LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &opt->setup);
663                         opt->setup.bmRequestType = num_id(argv[n + 1], "bmReqTyp");
664                         opt->setup.bRequest = num_id(argv[n + 2], "bReq");
665                         opt->setup.wValue = num_id(argv[n + 3], "wVal");
666                         opt->setup.wIndex = num_id(argv[n + 4], "wIndex");
667                         opt->setup.wLength = num_id(argv[n + 5], "wLen");
668                         if (opt->setup.wLength != 0) {
669                                 opt->buffer = malloc(opt->setup.wLength);
670                         } else {
671                                 opt->buffer = NULL;
672                         }
673
674                         n += 5;
675
676                         if (!(opt->setup.bmRequestType &
677                             LIBUSB20_ENDPOINT_IN)) {
678                                 /* copy in data */
679                                 t = (argc - n - 1);
680                                 if (t < opt->setup.wLength) {
681                                         err(1, "request data missing");
682                                 }
683                                 t = opt->setup.wLength;
684                                 while (t--) {
685                                         ((uint8_t *)opt->buffer)[t] =
686                                             num_id(argv[n + t + 1], "req_data");
687                                 }
688                                 n += opt->setup.wLength;
689                         }
690                         opt->got_do_request = 1;
691                         opt->got_any++;
692                         break;
693                 default:
694                         usage();
695                         break;
696                 }
697         }
698         if (opt->got_any) {
699                 /* flush out last command */
700                 flush_command(pbe, opt);
701         } else {
702                 /* list all the devices */
703                 opt->got_list = 1;
704                 opt->got_any++;
705                 flush_command(pbe, opt);
706         }
707         /* release data */
708         libusb20_be_free(pbe);
709
710         return (0);
711 }