xref: /dflybsd-src/share/examples/libusb20/control.c (revision 75d796ba91a5113779666919834b3cf2d51050fb)
1dacffe4aSSascha Wildner /* ----------------------------------------------------------------------------
2dacffe4aSSascha Wildner  * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
3dacffe4aSSascha Wildner  * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
4dacffe4aSSascha Wildner  * can do whatever you want with this stuff. If we meet some day, and you think
5dacffe4aSSascha Wildner  * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
6dacffe4aSSascha Wildner  * ----------------------------------------------------------------------------
7dacffe4aSSascha Wildner  *
8dacffe4aSSascha Wildner  * $FreeBSD: head/share/examples/libusb20/control.c 257779 2013-11-07 07:22:51Z hselasky $
9dacffe4aSSascha Wildner  */
10dacffe4aSSascha Wildner 
11dacffe4aSSascha Wildner /*
12dacffe4aSSascha Wildner  * Simple demo program to illustrate the handling of FreeBSD's
13dacffe4aSSascha Wildner  * libusb20.
14dacffe4aSSascha Wildner  */
15dacffe4aSSascha Wildner 
16dacffe4aSSascha Wildner /*
17dacffe4aSSascha Wildner  * Examples:
18dacffe4aSSascha Wildner  * Just list all VID:PID pairs
19dacffe4aSSascha Wildner  * ./control
20dacffe4aSSascha Wildner  *
21dacffe4aSSascha Wildner  * Standard device request GET_STATUS, report two bytes of status
22dacffe4aSSascha Wildner  * (bit 0 in the first byte returned is the "self powered" bit)
23dacffe4aSSascha Wildner  * ./control -v 0x3eb -p 0x2103 in std dev get_status 0 0 2
24dacffe4aSSascha Wildner  *
25dacffe4aSSascha Wildner  * Request input reports through the interrupt pipe from a mouse
26dacffe4aSSascha Wildner  * device (move the mouse around after issuing the command):
27dacffe4aSSascha Wildner  * ./control -v 0x093a -p 0x2516 -i 0x81
28dacffe4aSSascha Wildner  *
29dacffe4aSSascha Wildner  */
30dacffe4aSSascha Wildner 
31dacffe4aSSascha Wildner 
32dacffe4aSSascha Wildner #include <limits.h>
33dacffe4aSSascha Wildner #include <stdbool.h>
34dacffe4aSSascha Wildner #include <stdio.h>
35dacffe4aSSascha Wildner #include <stdint.h>
36dacffe4aSSascha Wildner #include <stdlib.h>
37dacffe4aSSascha Wildner #include <sysexits.h>
38dacffe4aSSascha Wildner #include <unistd.h>
39dacffe4aSSascha Wildner #include <string.h>
40dacffe4aSSascha Wildner 
41dacffe4aSSascha Wildner #include <libusb20.h>
42dacffe4aSSascha Wildner #include <libusb20_desc.h>
43dacffe4aSSascha Wildner 
44dacffe4aSSascha Wildner #include <sys/queue.h>
45dacffe4aSSascha Wildner 
46dacffe4aSSascha Wildner #include "util.h"
47dacffe4aSSascha Wildner 
48dacffe4aSSascha Wildner /*
49dacffe4aSSascha Wildner  * If you want to see the details of the internal datastructures
50dacffe4aSSascha Wildner  * in the debugger, unifdef the following.
51dacffe4aSSascha Wildner  */
52dacffe4aSSascha Wildner #ifdef DEBUG
53dacffe4aSSascha Wildner #  include "/usr/src/lib/libusb/libusb20_int.h"
54dacffe4aSSascha Wildner #endif
55dacffe4aSSascha Wildner 
56dacffe4aSSascha Wildner #define BUFLEN 64
57dacffe4aSSascha Wildner 
58dacffe4aSSascha Wildner #define TIMEOUT 5000 		/* 5 s */
59dacffe4aSSascha Wildner 
60dacffe4aSSascha Wildner int intr_ep;		/* endpoints */
61dacffe4aSSascha Wildner struct LIBUSB20_CONTROL_SETUP_DECODED setup;
62dacffe4aSSascha Wildner 
63dacffe4aSSascha Wildner uint8_t out_buf[BUFLEN];
64dacffe4aSSascha Wildner uint16_t out_len;
65dacffe4aSSascha Wildner 
66dacffe4aSSascha Wildner bool do_request;
67dacffe4aSSascha Wildner 
68dacffe4aSSascha Wildner static void
doit(struct libusb20_device * dev)69dacffe4aSSascha Wildner doit(struct libusb20_device *dev)
70dacffe4aSSascha Wildner {
71dacffe4aSSascha Wildner   int rv;
72dacffe4aSSascha Wildner 
73dacffe4aSSascha Wildner   if (do_request)
74dacffe4aSSascha Wildner     printf("doit(): bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\n",
75dacffe4aSSascha Wildner 	   setup.bmRequestType,
76dacffe4aSSascha Wildner 	   setup.bRequest,
77dacffe4aSSascha Wildner 	   setup.wValue,
78dacffe4aSSascha Wildner 	   setup.wIndex,
79dacffe4aSSascha Wildner 	   setup.wLength);
80dacffe4aSSascha Wildner 
81dacffe4aSSascha Wildner   /*
82dacffe4aSSascha Wildner    * Open the device, allocating memory for two possible (bulk or
83dacffe4aSSascha Wildner    * interrupt) transfers.
84dacffe4aSSascha Wildner    *
85dacffe4aSSascha Wildner    * If only control transfers are intended (via
86dacffe4aSSascha Wildner    * libusb20_dev_request_sync()), transfer_max can be given as 0.
87dacffe4aSSascha Wildner    */
88dacffe4aSSascha Wildner   if ((rv = libusb20_dev_open(dev, 1)) != 0)
89dacffe4aSSascha Wildner     {
90dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv));
91dacffe4aSSascha Wildner       return;
92dacffe4aSSascha Wildner     }
93dacffe4aSSascha Wildner 
94dacffe4aSSascha Wildner   /*
95dacffe4aSSascha Wildner    * If the device has more than one configuration, select the desired
96dacffe4aSSascha Wildner    * one here.
97dacffe4aSSascha Wildner    */
98dacffe4aSSascha Wildner   if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
99dacffe4aSSascha Wildner     {
100dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv));
101dacffe4aSSascha Wildner       return;
102dacffe4aSSascha Wildner     }
103dacffe4aSSascha Wildner 
104*75d796baSSascha Wildner   uint8_t *data = NULL;
105dacffe4aSSascha Wildner   uint16_t actlen;
106dacffe4aSSascha Wildner 
107dacffe4aSSascha Wildner   if ((setup.bmRequestType & 0x80) != 0)
108dacffe4aSSascha Wildner     {
109dacffe4aSSascha Wildner       /* this is an IN request, allocate a buffer */
110dacffe4aSSascha Wildner       data = malloc(setup.wLength);
111*75d796baSSascha Wildner       if (data == NULL)
112dacffe4aSSascha Wildner 	{
113dacffe4aSSascha Wildner 	  fprintf(stderr,
114dacffe4aSSascha Wildner 		  "Out of memory allocating %u bytes of reply buffer\n",
115dacffe4aSSascha Wildner 		  setup.wLength);
116dacffe4aSSascha Wildner 	  return;
117dacffe4aSSascha Wildner 	}
118dacffe4aSSascha Wildner     }
119dacffe4aSSascha Wildner   else
120dacffe4aSSascha Wildner     data = out_buf;
121dacffe4aSSascha Wildner 
122dacffe4aSSascha Wildner   if (do_request)
123dacffe4aSSascha Wildner     {
124dacffe4aSSascha Wildner       if ((rv = libusb20_dev_request_sync(dev, &setup, data,
125dacffe4aSSascha Wildner 					  &actlen,
126dacffe4aSSascha Wildner 					  TIMEOUT,
127dacffe4aSSascha Wildner 					  0 /* flags */)) != 0)
128dacffe4aSSascha Wildner 	{
129dacffe4aSSascha Wildner 	  fprintf(stderr,
130dacffe4aSSascha Wildner 		  "libusb20_dev_request_sync: %s\n", libusb20_strerror(rv));
131dacffe4aSSascha Wildner 	}
132dacffe4aSSascha Wildner       printf("sent %d bytes\n", actlen);
133dacffe4aSSascha Wildner       if ((setup.bmRequestType & 0x80) != 0)
134dacffe4aSSascha Wildner 	{
135dacffe4aSSascha Wildner 	  print_formatted(data, (uint32_t)setup.wLength);
136dacffe4aSSascha Wildner 	  free(data);
137dacffe4aSSascha Wildner 	}
138dacffe4aSSascha Wildner     }
139dacffe4aSSascha Wildner 
140dacffe4aSSascha Wildner   if (intr_ep != 0)
141dacffe4aSSascha Wildner     {
142dacffe4aSSascha Wildner       /*
143dacffe4aSSascha Wildner        * One transfer has been requested in libusb20_dev_open() above;
144dacffe4aSSascha Wildner        * obtain the corresponding transfer struct pointer.
145dacffe4aSSascha Wildner        */
146dacffe4aSSascha Wildner       struct libusb20_transfer *xfr_intr = libusb20_tr_get_pointer(dev, 0);
147dacffe4aSSascha Wildner 
148dacffe4aSSascha Wildner       if (xfr_intr == NULL)
149dacffe4aSSascha Wildner 	{
150dacffe4aSSascha Wildner 	  fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv));
151dacffe4aSSascha Wildner 	  return;
152dacffe4aSSascha Wildner 	}
153dacffe4aSSascha Wildner 
154dacffe4aSSascha Wildner       /*
155dacffe4aSSascha Wildner        * Open the interrupt transfer.
156dacffe4aSSascha Wildner        */
157dacffe4aSSascha Wildner       if ((rv = libusb20_tr_open(xfr_intr, 0, 1, intr_ep)) != 0)
158dacffe4aSSascha Wildner 	{
159dacffe4aSSascha Wildner 	  fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
160dacffe4aSSascha Wildner 	  return;
161dacffe4aSSascha Wildner 	}
162dacffe4aSSascha Wildner 
163dacffe4aSSascha Wildner       uint8_t in_buf[BUFLEN];
164dacffe4aSSascha Wildner       uint32_t rlen;
165dacffe4aSSascha Wildner 
166dacffe4aSSascha Wildner       if ((rv = libusb20_tr_bulk_intr_sync(xfr_intr, in_buf, BUFLEN, &rlen, TIMEOUT))
167dacffe4aSSascha Wildner 	  != 0)
168dacffe4aSSascha Wildner 	{
169dacffe4aSSascha Wildner 	  fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv));
170dacffe4aSSascha Wildner 	}
171dacffe4aSSascha Wildner       printf("received %d bytes\n", rlen);
172dacffe4aSSascha Wildner       if (rlen > 0)
173dacffe4aSSascha Wildner 	print_formatted(in_buf, rlen);
174dacffe4aSSascha Wildner 
175dacffe4aSSascha Wildner       libusb20_tr_close(xfr_intr);
176dacffe4aSSascha Wildner     }
177dacffe4aSSascha Wildner 
178dacffe4aSSascha Wildner   libusb20_dev_close(dev);
179dacffe4aSSascha Wildner }
180dacffe4aSSascha Wildner 
181dacffe4aSSascha Wildner static void
usage(void)182dacffe4aSSascha Wildner usage(void)
183dacffe4aSSascha Wildner {
184dacffe4aSSascha Wildner   fprintf(stderr,
185dacffe4aSSascha Wildner 	  "Usage ./usb [-i <INTR_EP>] -v <VID> -p <PID> [dir type rcpt req wValue wIndex wLength [<outdata> ...]]\n");
186dacffe4aSSascha Wildner   exit(EX_USAGE);
187dacffe4aSSascha Wildner }
188dacffe4aSSascha Wildner 
189dacffe4aSSascha Wildner static const char *reqnames[] =
190dacffe4aSSascha Wildner {
191dacffe4aSSascha Wildner   "get_status",
192dacffe4aSSascha Wildner   "clear_feature",
193dacffe4aSSascha Wildner   "res1",
194dacffe4aSSascha Wildner   "set_feature",
195dacffe4aSSascha Wildner   "res2",
196dacffe4aSSascha Wildner   "set_address",
197dacffe4aSSascha Wildner   "get_descriptor",
198dacffe4aSSascha Wildner   "set_descriptor",
199dacffe4aSSascha Wildner   "get_configuration",
200dacffe4aSSascha Wildner   "set_configuration",
201dacffe4aSSascha Wildner   "get_interface",
202dacffe4aSSascha Wildner   "set_interface",
203dacffe4aSSascha Wildner   "synch_frame",
204dacffe4aSSascha Wildner };
205dacffe4aSSascha Wildner 
206dacffe4aSSascha Wildner static int
get_req(const char * reqname)207dacffe4aSSascha Wildner get_req(const char *reqname)
208dacffe4aSSascha Wildner {
209dacffe4aSSascha Wildner   size_t i;
210dacffe4aSSascha Wildner   size_t l = strlen(reqname);
211dacffe4aSSascha Wildner 
212dacffe4aSSascha Wildner   for (i = 0;
213dacffe4aSSascha Wildner        i < sizeof reqnames / sizeof reqnames[0];
214dacffe4aSSascha Wildner        i++)
215dacffe4aSSascha Wildner     if (strncasecmp(reqname, reqnames[i], l) == 0)
216dacffe4aSSascha Wildner       return i;
217dacffe4aSSascha Wildner 
218dacffe4aSSascha Wildner   return strtoul(reqname, 0, 0);
219dacffe4aSSascha Wildner }
220dacffe4aSSascha Wildner 
221dacffe4aSSascha Wildner 
222dacffe4aSSascha Wildner static int
parse_req(int argc,char ** argv)223dacffe4aSSascha Wildner parse_req(int argc, char **argv)
224dacffe4aSSascha Wildner {
225dacffe4aSSascha Wildner   int idx;
226dacffe4aSSascha Wildner   uint8_t rt = 0;
227dacffe4aSSascha Wildner 
228dacffe4aSSascha Wildner   for (idx = 0; argc != 0 && idx <= 6; argc--, idx++)
229dacffe4aSSascha Wildner     switch (idx)
230dacffe4aSSascha Wildner       {
231dacffe4aSSascha Wildner       case 0:
232dacffe4aSSascha Wildner 	/* dir[ection]: i[n] | o[ut] */
233dacffe4aSSascha Wildner 	if (*argv[idx] == 'i')
234dacffe4aSSascha Wildner 	  rt |= 0x80;
235dacffe4aSSascha Wildner 	else if (*argv[idx] == 'o')
236dacffe4aSSascha Wildner 	  /* nop */;
237dacffe4aSSascha Wildner 	else
238dacffe4aSSascha Wildner 	  {
239dacffe4aSSascha Wildner 	    fprintf(stderr, "request direction must be \"in\" or \"out\" (got %s)\n",
240dacffe4aSSascha Wildner 		    argv[idx]);
241dacffe4aSSascha Wildner 	    return -1;
242dacffe4aSSascha Wildner 	  }
243dacffe4aSSascha Wildner 	break;
244dacffe4aSSascha Wildner 
245dacffe4aSSascha Wildner       case 1:
246dacffe4aSSascha Wildner 	/* type: s[tandard] | c[lass] | v[endor] */
247dacffe4aSSascha Wildner 	if (*argv[idx] == 's')
248dacffe4aSSascha Wildner 	  /* nop */;
249dacffe4aSSascha Wildner 	else if (*argv[idx] == 'c')
250dacffe4aSSascha Wildner 	  rt |= 0x20;
251dacffe4aSSascha Wildner 	else if (*argv[idx] == 'v')
252dacffe4aSSascha Wildner 	  rt |= 0x40;
253dacffe4aSSascha Wildner 	else
254dacffe4aSSascha Wildner 	  {
255dacffe4aSSascha Wildner 	    fprintf(stderr,
256dacffe4aSSascha Wildner 		    "request type must be one of \"standard\", \"class\", or \"vendor\" (got %s)\n",
257dacffe4aSSascha Wildner 		    argv[idx]);
258dacffe4aSSascha Wildner 	    return -1;
259dacffe4aSSascha Wildner 	  }
260dacffe4aSSascha Wildner 	break;
261dacffe4aSSascha Wildner 
262dacffe4aSSascha Wildner       case 2:
263dacffe4aSSascha Wildner 	/* rcpt: d[evice], i[nterface], e[ndpoint], o[ther] */
264dacffe4aSSascha Wildner 	if (*argv[idx] == 'd')
265dacffe4aSSascha Wildner 	  /* nop */;
266dacffe4aSSascha Wildner 	else if (*argv[idx] == 'i')
267dacffe4aSSascha Wildner 	  rt |= 1;
268dacffe4aSSascha Wildner 	else if (*argv[idx] == 'e')
269dacffe4aSSascha Wildner 	  rt |= 2;
270dacffe4aSSascha Wildner 	else if (*argv[idx] == 'o')
271dacffe4aSSascha Wildner 	  rt |= 3;
272dacffe4aSSascha Wildner 	else
273dacffe4aSSascha Wildner 	  {
274dacffe4aSSascha Wildner 	    fprintf(stderr,
275dacffe4aSSascha Wildner 		    "recipient must be one of \"device\", \"interface\", \"endpoint\", or \"other\" (got %s)\n",
276dacffe4aSSascha Wildner 		    argv[idx]);
277dacffe4aSSascha Wildner 	    return -1;
278dacffe4aSSascha Wildner 	  }
279dacffe4aSSascha Wildner 	setup.bmRequestType = rt;
280dacffe4aSSascha Wildner 	break;
281dacffe4aSSascha Wildner 
282dacffe4aSSascha Wildner       case 3:
283dacffe4aSSascha Wildner 	setup.bRequest = get_req(argv[idx]);
284dacffe4aSSascha Wildner 	break;
285dacffe4aSSascha Wildner 
286dacffe4aSSascha Wildner       case 4:
287dacffe4aSSascha Wildner 	setup.wValue = strtoul(argv[idx], 0, 0);
288dacffe4aSSascha Wildner 	break;
289dacffe4aSSascha Wildner 
290dacffe4aSSascha Wildner       case 5:
291dacffe4aSSascha Wildner 	setup.wIndex = strtoul(argv[idx], 0, 0);
292dacffe4aSSascha Wildner 	break;
293dacffe4aSSascha Wildner 
294dacffe4aSSascha Wildner       case 6:
295dacffe4aSSascha Wildner 	setup.wLength = strtoul(argv[idx], 0, 0);
296dacffe4aSSascha Wildner 	break;
297dacffe4aSSascha Wildner       }
298dacffe4aSSascha Wildner 
299dacffe4aSSascha Wildner   return argc;
300dacffe4aSSascha Wildner }
301dacffe4aSSascha Wildner 
302dacffe4aSSascha Wildner 
303dacffe4aSSascha Wildner int
main(int argc,char ** argv)304dacffe4aSSascha Wildner main(int argc, char **argv)
305dacffe4aSSascha Wildner {
306dacffe4aSSascha Wildner   unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
307dacffe4aSSascha Wildner   int c;
308dacffe4aSSascha Wildner 
309dacffe4aSSascha Wildner   /*
310dacffe4aSSascha Wildner    * Initialize setup struct.  This step is required, and initializes
311dacffe4aSSascha Wildner    * internal fields in the struct.
312dacffe4aSSascha Wildner    *
313dacffe4aSSascha Wildner    * All the "public" fields are named exactly the way as the USB
314dacffe4aSSascha Wildner    * standard describes them, namely:
315dacffe4aSSascha Wildner    *
316dacffe4aSSascha Wildner    *	setup.bmRequestType: bitmask, bit 7 is direction
317dacffe4aSSascha Wildner    *	                              bits 6/5 is request type
318dacffe4aSSascha Wildner    *	                                       (standard, class, vendor)
319dacffe4aSSascha Wildner    *	                              bits 4..0 is recipient
320dacffe4aSSascha Wildner    *	                                       (device, interface, endpoint,
321dacffe4aSSascha Wildner    *	                                        other)
322dacffe4aSSascha Wildner    *	setup.bRequest:      the request itself (see get_req() for standard
323dacffe4aSSascha Wildner    *	                                         requests, or specific value)
324dacffe4aSSascha Wildner    *	setup.wValue:        a 16-bit value
325dacffe4aSSascha Wildner    *	setup.wIndex:        another 16-bit value
326dacffe4aSSascha Wildner    *	setup.wLength:       length of associated data transfer, direction
327dacffe4aSSascha Wildner    *	                     depends on bit 7 of bmRequestType
328dacffe4aSSascha Wildner    */
329dacffe4aSSascha Wildner   LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
330dacffe4aSSascha Wildner 
331dacffe4aSSascha Wildner   while ((c = getopt(argc, argv, "i:p:v:")) != -1)
332dacffe4aSSascha Wildner     switch (c)
333dacffe4aSSascha Wildner       {
334dacffe4aSSascha Wildner       case 'i':
335dacffe4aSSascha Wildner 	intr_ep = strtol(optarg, NULL, 0);
336dacffe4aSSascha Wildner 	break;
337dacffe4aSSascha Wildner 
338dacffe4aSSascha Wildner       case 'p':
339dacffe4aSSascha Wildner 	pid = strtol(optarg, NULL, 0);
340dacffe4aSSascha Wildner 	break;
341dacffe4aSSascha Wildner 
342dacffe4aSSascha Wildner       case 'v':
343dacffe4aSSascha Wildner 	vid = strtol(optarg, NULL, 0);
344dacffe4aSSascha Wildner 	break;
345dacffe4aSSascha Wildner 
346dacffe4aSSascha Wildner       default:
347dacffe4aSSascha Wildner 	usage();
348dacffe4aSSascha Wildner 	break;
349dacffe4aSSascha Wildner       }
350dacffe4aSSascha Wildner   argc -= optind;
351dacffe4aSSascha Wildner   argv += optind;
352dacffe4aSSascha Wildner 
353dacffe4aSSascha Wildner   if (vid != UINT_MAX || pid != UINT_MAX)
354dacffe4aSSascha Wildner     {
355dacffe4aSSascha Wildner       if (intr_ep != 0 && (intr_ep & 0x80) == 0)
356dacffe4aSSascha Wildner 	{
357dacffe4aSSascha Wildner 	  fprintf(stderr, "Interrupt endpoint must be of type IN\n");
358dacffe4aSSascha Wildner 	  usage();
359dacffe4aSSascha Wildner 	}
360dacffe4aSSascha Wildner 
361dacffe4aSSascha Wildner       if (argc > 0)
362dacffe4aSSascha Wildner 	{
363dacffe4aSSascha Wildner 	  do_request = true;
364dacffe4aSSascha Wildner 
365dacffe4aSSascha Wildner 	  int rv = parse_req(argc, argv);
366dacffe4aSSascha Wildner 	  if (rv < 0)
367dacffe4aSSascha Wildner 	    return EX_USAGE;
368dacffe4aSSascha Wildner 	  argc = rv;
369dacffe4aSSascha Wildner 
370dacffe4aSSascha Wildner 	  if (argc > 0)
371dacffe4aSSascha Wildner 	    {
372dacffe4aSSascha Wildner 	      for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
373dacffe4aSSascha Wildner 		{
374dacffe4aSSascha Wildner 		  unsigned n = strtoul(argv[out_len], 0, 0);
375dacffe4aSSascha Wildner 		  if (n > 255)
376dacffe4aSSascha Wildner 		    fprintf(stderr,
377dacffe4aSSascha Wildner 			    "Warning: data #%d 0x%0x > 0xff, truncating\n",
378dacffe4aSSascha Wildner 			    out_len, n);
379dacffe4aSSascha Wildner 		  out_buf[out_len] = (uint8_t)n;
380dacffe4aSSascha Wildner 		}
381dacffe4aSSascha Wildner 	      out_len++;
382dacffe4aSSascha Wildner 	      if (argc > 0)
383dacffe4aSSascha Wildner 		fprintf(stderr,
384dacffe4aSSascha Wildner 			"Data count exceeds maximum of %d, ignoring %d elements\n",
385dacffe4aSSascha Wildner 			BUFLEN, optind);
386dacffe4aSSascha Wildner 	    }
387dacffe4aSSascha Wildner 	}
388dacffe4aSSascha Wildner     }
389dacffe4aSSascha Wildner 
390dacffe4aSSascha Wildner   struct libusb20_backend *be;
391dacffe4aSSascha Wildner   struct libusb20_device *dev;
392dacffe4aSSascha Wildner 
393dacffe4aSSascha Wildner   if ((be = libusb20_be_alloc_default()) == NULL)
394dacffe4aSSascha Wildner     {
395dacffe4aSSascha Wildner       perror("libusb20_be_alloc()");
396dacffe4aSSascha Wildner       return 1;
397dacffe4aSSascha Wildner     }
398dacffe4aSSascha Wildner 
399dacffe4aSSascha Wildner   dev = NULL;
400dacffe4aSSascha Wildner   while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
401dacffe4aSSascha Wildner     {
402dacffe4aSSascha Wildner       struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
403dacffe4aSSascha Wildner       libusb20_dev_get_device_desc(dev);
404dacffe4aSSascha Wildner 
405dacffe4aSSascha Wildner       printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
406dacffe4aSSascha Wildner 	     libusb20_dev_get_desc(dev),
407dacffe4aSSascha Wildner 	     ddp->idVendor, ddp->idProduct);
408dacffe4aSSascha Wildner 
409dacffe4aSSascha Wildner       if (ddp->idVendor == vid && ddp->idProduct == pid)
410dacffe4aSSascha Wildner 	doit(dev);
411dacffe4aSSascha Wildner     }
412dacffe4aSSascha Wildner 
413dacffe4aSSascha Wildner   libusb20_be_free(be);
414dacffe4aSSascha Wildner   return 0;
415dacffe4aSSascha Wildner }
416