control.c revision 238603
1238603Sjoerg/* ----------------------------------------------------------------------------
2238603Sjoerg * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
3238603Sjoerg * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
4238603Sjoerg * can do whatever you want with this stuff. If we meet some day, and you think
5238603Sjoerg * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
6238603Sjoerg * ----------------------------------------------------------------------------
7238603Sjoerg *
8238603Sjoerg * $FreeBSD: head/share/examples/libusb20/control.c 238603 2012-07-18 21:30:17Z joerg $
9238603Sjoerg */
10238603Sjoerg
11238603Sjoerg/*
12238603Sjoerg * Simple demo program to illustrate the handling of FreeBSD's
13238603Sjoerg * libusb20.
14238603Sjoerg *
15238603Sjoerg * XXX
16238603Sjoerg */
17238603Sjoerg
18238603Sjoerg/*
19238603Sjoerg * Examples:
20238603Sjoerg * Just list all VID:PID pairs
21238603Sjoerg * ./control
22238603Sjoerg *
23238603Sjoerg * Standard device request GET_STATUS, report two bytes of status
24238603Sjoerg * (bit 0 in the first byte returned is the "self powered" bit)
25238603Sjoerg * ./control -v 0x3eb -p 0x2103 in std dev get_status 0 0 2
26238603Sjoerg *
27238603Sjoerg * Request input reports through the interrupt pipe from a mouse
28238603Sjoerg * device (move the mouse around after issuing the command):
29238603Sjoerg * ./control -v 0x093a -p 0x2516 -i 0x81
30238603Sjoerg *
31238603Sjoerg */
32238603Sjoerg
33238603Sjoerg
34238603Sjoerg#include <limits.h>
35238603Sjoerg#include <stdbool.h>
36238603Sjoerg#include <stdio.h>
37238603Sjoerg#include <stdint.h>
38238603Sjoerg#include <stdlib.h>
39238603Sjoerg#include <sysexits.h>
40238603Sjoerg#include <unistd.h>
41238603Sjoerg
42238603Sjoerg#include <libusb20.h>
43238603Sjoerg#include <libusb20_desc.h>
44238603Sjoerg
45238603Sjoerg#include <sys/queue.h>
46238603Sjoerg
47238603Sjoerg/*
48238603Sjoerg * If you want to see the details of the internal datastructures
49238603Sjoerg * in the debugger, unifdef the following.
50238603Sjoerg */
51238603Sjoerg#ifdef DEBUG
52238603Sjoerg#  include "/usr/src/lib/libusb/libusb20_int.h"
53238603Sjoerg#endif
54238603Sjoerg
55238603Sjoerg#define BUFLEN 64
56238603Sjoerg
57238603Sjoerg#define TIMEOUT 5000 		/* 5 s */
58238603Sjoerg
59238603Sjoergint intr_ep;		/* endpoints */
60238603Sjoergstruct LIBUSB20_CONTROL_SETUP_DECODED setup;
61238603Sjoerg
62238603Sjoerguint8_t out_buf[BUFLEN];
63238603Sjoerguint16_t out_len;
64238603Sjoerg
65238603Sjoergbool do_request;
66238603Sjoerg
67238603Sjoergstatic void
68238603Sjoergdoit(struct libusb20_device *dev)
69238603Sjoerg{
70238603Sjoerg  int rv;
71238603Sjoerg
72238603Sjoerg  if (do_request)
73238603Sjoerg    printf("doit(): bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\n",
74238603Sjoerg	   setup.bmRequestType,
75238603Sjoerg	   setup.bRequest,
76238603Sjoerg	   setup.wValue,
77238603Sjoerg	   setup.wIndex,
78238603Sjoerg	   setup.wLength);
79238603Sjoerg
80238603Sjoerg  /*
81238603Sjoerg   * Open the device, allocating memory for two possible (bulk or
82238603Sjoerg   * interrupt) transfers.
83238603Sjoerg   *
84238603Sjoerg   * If only control transfers are intended (via
85238603Sjoerg   * libusb20_dev_request_sync()), transfer_max can be given as 0.
86238603Sjoerg   */
87238603Sjoerg  if ((rv = libusb20_dev_open(dev, 1)) != 0)
88238603Sjoerg    {
89238603Sjoerg      fprintf(stderr, "libusb20_dev_open: %s\n", usb_error(rv));
90238603Sjoerg      return;
91238603Sjoerg    }
92238603Sjoerg
93238603Sjoerg  /*
94238603Sjoerg   * If the device has more than one configuration, select the desired
95238603Sjoerg   * one here.
96238603Sjoerg   */
97238603Sjoerg  if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
98238603Sjoerg    {
99238603Sjoerg      fprintf(stderr, "libusb20_dev_set_config_index: %s\n", usb_error(rv));
100238603Sjoerg      return;
101238603Sjoerg    }
102238603Sjoerg
103238603Sjoerg  uint8_t *data = 0;
104238603Sjoerg  uint16_t actlen;
105238603Sjoerg
106238603Sjoerg  if ((setup.bmRequestType & 0x80) != 0)
107238603Sjoerg    {
108238603Sjoerg      /* this is an IN request, allocate a buffer */
109238603Sjoerg      data = malloc(setup.wLength);
110238603Sjoerg      if (data == 0)
111238603Sjoerg	{
112238603Sjoerg	  fprintf(stderr,
113238603Sjoerg		  "Out of memory allocating %u bytes of reply buffer\n",
114238603Sjoerg		  setup.wLength);
115238603Sjoerg	  return;
116238603Sjoerg	}
117238603Sjoerg    }
118238603Sjoerg  else
119238603Sjoerg    data = out_buf;
120238603Sjoerg
121238603Sjoerg  if (do_request)
122238603Sjoerg    {
123238603Sjoerg      if ((rv = libusb20_dev_request_sync(dev, &setup, data,
124238603Sjoerg					  &actlen,
125238603Sjoerg					  TIMEOUT,
126238603Sjoerg					  0 /* flags */)) != 0)
127238603Sjoerg	{
128238603Sjoerg	  fprintf(stderr,
129238603Sjoerg		  "libusb20_dev_request_sync: %s\n", usb_error(rv));
130238603Sjoerg	}
131238603Sjoerg      printf("sent %d bytes\n", actlen);
132238603Sjoerg      if ((setup.bmRequestType & 0x80) != 0)
133238603Sjoerg	{
134238603Sjoerg	  print_formatted(data, (uint32_t)setup.wLength);
135238603Sjoerg	  free(data);
136238603Sjoerg	}
137238603Sjoerg    }
138238603Sjoerg
139238603Sjoerg  if (intr_ep != 0)
140238603Sjoerg    {
141238603Sjoerg      /*
142238603Sjoerg       * One transfer has been requested in libusb20_dev_open() above;
143238603Sjoerg       * obtain the corresponding transfer struct pointer.
144238603Sjoerg       */
145238603Sjoerg      struct libusb20_transfer *xfr_intr = libusb20_tr_get_pointer(dev, 0);
146238603Sjoerg
147238603Sjoerg      if (xfr_intr == NULL)
148238603Sjoerg	{
149238603Sjoerg	  fprintf(stderr, "libusb20_tr_get_pointer: %s\n", usb_error(rv));
150238603Sjoerg	  return;
151238603Sjoerg	}
152238603Sjoerg
153238603Sjoerg      /*
154238603Sjoerg       * Open the interrupt transfer.
155238603Sjoerg       */
156238603Sjoerg      if ((rv = libusb20_tr_open(xfr_intr, 0, 1, intr_ep)) != 0)
157238603Sjoerg	{
158238603Sjoerg	  fprintf(stderr, "libusb20_tr_open: %s\n", usb_error(rv));
159238603Sjoerg	  return;
160238603Sjoerg	}
161238603Sjoerg
162238603Sjoerg      uint8_t in_buf[BUFLEN];
163238603Sjoerg      uint32_t rlen;
164238603Sjoerg
165238603Sjoerg      if ((rv = libusb20_tr_bulk_intr_sync(xfr_intr, in_buf, BUFLEN, &rlen, TIMEOUT))
166238603Sjoerg	  != 0)
167238603Sjoerg	{
168238603Sjoerg	  fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", usb_error(rv));
169238603Sjoerg	}
170238603Sjoerg      printf("received %d bytes\n", rlen);
171238603Sjoerg      if (rlen > 0)
172238603Sjoerg	print_formatted(in_buf, rlen);
173238603Sjoerg
174238603Sjoerg      libusb20_tr_close(xfr_intr);
175238603Sjoerg    }
176238603Sjoerg
177238603Sjoerg  libusb20_dev_close(dev);
178238603Sjoerg}
179238603Sjoerg
180238603Sjoergstatic void
181238603Sjoergusage(void)
182238603Sjoerg{
183238603Sjoerg  fprintf(stderr,
184238603Sjoerg	  "Usage ./usb [-i <INTR_EP>] -v <VID> -p <PID> [dir type rcpt req wValue wIndex wLength [<outdata> ...]]\n");
185238603Sjoerg  exit(EX_USAGE);
186238603Sjoerg}
187238603Sjoerg
188238603Sjoergstatic const char *reqnames[] =
189238603Sjoerg{
190238603Sjoerg  "get_status",
191238603Sjoerg  "clear_feature",
192238603Sjoerg  "res1",
193238603Sjoerg  "set_feature",
194238603Sjoerg  "res2",
195238603Sjoerg  "set_address",
196238603Sjoerg  "get_descriptor",
197238603Sjoerg  "set_descriptor",
198238603Sjoerg  "get_configuration",
199238603Sjoerg  "set_configuration",
200238603Sjoerg  "get_interface",
201238603Sjoerg  "set_interface",
202238603Sjoerg  "synch_frame",
203238603Sjoerg};
204238603Sjoerg
205238603Sjoergstatic int
206238603Sjoergget_req(const char *reqname)
207238603Sjoerg{
208238603Sjoerg  size_t i;
209238603Sjoerg  size_t l = strlen(reqname);
210238603Sjoerg
211238603Sjoerg  for (i = 0;
212238603Sjoerg       i < sizeof reqnames / sizeof reqnames[0];
213238603Sjoerg       i++)
214238603Sjoerg    if (strncasecmp(reqname, reqnames[i], l) == 0)
215238603Sjoerg      return i;
216238603Sjoerg
217238603Sjoerg  return strtoul(reqname, 0, 0);
218238603Sjoerg}
219238603Sjoerg
220238603Sjoerg
221238603Sjoergstatic int
222238603Sjoergparse_req(int argc, char **argv)
223238603Sjoerg{
224238603Sjoerg  int idx;
225238603Sjoerg  uint8_t rt = 0;
226238603Sjoerg
227238603Sjoerg  for (idx = 0; argc != 0 && idx <= 6; argc--, idx++)
228238603Sjoerg    switch (idx)
229238603Sjoerg      {
230238603Sjoerg      case 0:
231238603Sjoerg	/* dir[ection]: i[n] | o[ut] */
232238603Sjoerg	if (*argv[idx] == 'i')
233238603Sjoerg	  rt |= 0x80;
234238603Sjoerg	else if (*argv[idx] == 'o')
235238603Sjoerg	  /* nop */;
236238603Sjoerg	else
237238603Sjoerg	  {
238238603Sjoerg	    fprintf(stderr, "request direction must be \"in\" or \"out\" (got %s)\n",
239238603Sjoerg		    argv[idx]);
240238603Sjoerg	    return -1;
241238603Sjoerg	  }
242238603Sjoerg	break;
243238603Sjoerg
244238603Sjoerg      case 1:
245238603Sjoerg	/* type: s[tandard] | c[lass] | v[endor] */
246238603Sjoerg	if (*argv[idx] == 's')
247238603Sjoerg	  /* nop */;
248238603Sjoerg	else if (*argv[idx] == 'c')
249238603Sjoerg	  rt |= 0x20;
250238603Sjoerg	else if (*argv[idx] == 'v')
251238603Sjoerg	  rt |= 0x40;
252238603Sjoerg	else
253238603Sjoerg	  {
254238603Sjoerg	    fprintf(stderr,
255238603Sjoerg		    "request type must be one of \"standard\", \"class\", or \"vendor\" (got %s)\n",
256238603Sjoerg		    argv[idx]);
257238603Sjoerg	    return -1;
258238603Sjoerg	  }
259238603Sjoerg	break;
260238603Sjoerg
261238603Sjoerg      case 2:
262238603Sjoerg	/* rcpt: d[evice], i[nterface], e[ndpoint], o[ther] */
263238603Sjoerg	if (*argv[idx] == 'd')
264238603Sjoerg	  /* nop */;
265238603Sjoerg	else if (*argv[idx] == 'i')
266238603Sjoerg	  rt |= 1;
267238603Sjoerg	else if (*argv[idx] == 'e')
268238603Sjoerg	  rt |= 2;
269238603Sjoerg	else if (*argv[idx] == 'o')
270238603Sjoerg	  rt |= 3;
271238603Sjoerg	else
272238603Sjoerg	  {
273238603Sjoerg	    fprintf(stderr,
274238603Sjoerg		    "recipient must be one of \"device\", \"interface\", \"endpoint\", or \"other\" (got %s)\n",
275238603Sjoerg		    argv[idx]);
276238603Sjoerg	    return -1;
277238603Sjoerg	  }
278238603Sjoerg	setup.bmRequestType = rt;
279238603Sjoerg	break;
280238603Sjoerg
281238603Sjoerg      case 3:
282238603Sjoerg	setup.bRequest = get_req(argv[idx]);
283238603Sjoerg	break;
284238603Sjoerg
285238603Sjoerg      case 4:
286238603Sjoerg	setup.wValue = strtoul(argv[idx], 0, 0);
287238603Sjoerg	break;
288238603Sjoerg
289238603Sjoerg      case 5:
290238603Sjoerg	setup.wIndex = strtoul(argv[idx], 0, 0);
291238603Sjoerg	break;
292238603Sjoerg
293238603Sjoerg      case 6:
294238603Sjoerg	setup.wLength = strtoul(argv[idx], 0, 0);
295238603Sjoerg	break;
296238603Sjoerg      }
297238603Sjoerg
298238603Sjoerg  return argc;
299238603Sjoerg}
300238603Sjoerg
301238603Sjoerg
302238603Sjoergint
303238603Sjoergmain(int argc, char **argv)
304238603Sjoerg{
305238603Sjoerg  unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
306238603Sjoerg  int c;
307238603Sjoerg
308238603Sjoerg  /*
309238603Sjoerg   * Initialize setup struct.  This step is required, and initializes
310238603Sjoerg   * internal fields in the struct.
311238603Sjoerg   *
312238603Sjoerg   * All the "public" fields are named exactly the way as the USB
313238603Sjoerg   * standard describes them, namely:
314238603Sjoerg   *
315238603Sjoerg   *	setup.bmRequestType: bitmask, bit 7 is direction
316238603Sjoerg   *	                              bits 6/5 is request type
317238603Sjoerg   *	                                       (standard, class, vendor)
318238603Sjoerg   *	                              bits 4..0 is recipient
319238603Sjoerg   *	                                       (device, interface, endpoint,
320238603Sjoerg   *	                                        other)
321238603Sjoerg   *	setup.bRequest:      the request itself (see get_req() for standard
322238603Sjoerg   *	                                         requests, or specific value)
323238603Sjoerg   *	setup.wValue:        a 16-bit value
324238603Sjoerg   *	setup.wIndex:        another 16-bit value
325238603Sjoerg   *	setup.wLength:       length of associated data transfer, direction
326238603Sjoerg   *	                     depends on bit 7 of bmRequestType
327238603Sjoerg   */
328238603Sjoerg  LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
329238603Sjoerg
330238603Sjoerg  while ((c = getopt(argc, argv, "i:p:v:")) != -1)
331238603Sjoerg    switch (c)
332238603Sjoerg      {
333238603Sjoerg      case 'i':
334238603Sjoerg	intr_ep = strtol(optarg, NULL, 0);
335238603Sjoerg	break;
336238603Sjoerg
337238603Sjoerg      case 'p':
338238603Sjoerg	pid = strtol(optarg, NULL, 0);
339238603Sjoerg	break;
340238603Sjoerg
341238603Sjoerg      case 'v':
342238603Sjoerg	vid = strtol(optarg, NULL, 0);
343238603Sjoerg	break;
344238603Sjoerg
345238603Sjoerg      default:
346238603Sjoerg	usage();
347238603Sjoerg	break;
348238603Sjoerg      }
349238603Sjoerg  argc -= optind;
350238603Sjoerg  argv += optind;
351238603Sjoerg
352238603Sjoerg  if (vid != UINT_MAX || pid != UINT_MAX)
353238603Sjoerg    {
354238603Sjoerg      if (intr_ep != 0 && (intr_ep & 0x80) == 0)
355238603Sjoerg	{
356238603Sjoerg	  fprintf(stderr, "Interrupt endpoint must be of type IN\n");
357238603Sjoerg	  usage();
358238603Sjoerg	}
359238603Sjoerg
360238603Sjoerg      if (argc > 0)
361238603Sjoerg	{
362238603Sjoerg	  do_request = true;
363238603Sjoerg
364238603Sjoerg	  int rv = parse_req(argc, argv);
365238603Sjoerg	  if (rv < 0)
366238603Sjoerg	    return EX_USAGE;
367238603Sjoerg	  argc = rv;
368238603Sjoerg
369238603Sjoerg	  if (argc > 0)
370238603Sjoerg	    {
371238603Sjoerg	      for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
372238603Sjoerg		{
373238603Sjoerg		  unsigned n = strtoul(argv[out_len], 0, 0);
374238603Sjoerg		  if (n > 255)
375238603Sjoerg		    fprintf(stderr,
376238603Sjoerg			    "Warning: data #%d 0x%0x > 0xff, truncating\n",
377238603Sjoerg			    out_len, n);
378238603Sjoerg		  out_buf[out_len] = (uint8_t)n;
379238603Sjoerg		}
380238603Sjoerg	      out_len++;
381238603Sjoerg	      if (argc > 0)
382238603Sjoerg		fprintf(stderr,
383238603Sjoerg			"Data count exceeds maximum of %d, ignoring %d elements\n",
384238603Sjoerg			BUFLEN, optind);
385238603Sjoerg	    }
386238603Sjoerg	}
387238603Sjoerg    }
388238603Sjoerg
389238603Sjoerg  struct libusb20_backend *be;
390238603Sjoerg  struct libusb20_device *dev;
391238603Sjoerg
392238603Sjoerg  if ((be = libusb20_be_alloc_default()) == NULL)
393238603Sjoerg    {
394238603Sjoerg      perror("libusb20_be_alloc()");
395238603Sjoerg      return 1;
396238603Sjoerg    }
397238603Sjoerg
398238603Sjoerg  dev = NULL;
399238603Sjoerg  while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
400238603Sjoerg    {
401238603Sjoerg      struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
402238603Sjoerg      libusb20_dev_get_device_desc(dev);
403238603Sjoerg
404238603Sjoerg      printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
405238603Sjoerg	     libusb20_dev_get_desc(dev),
406238603Sjoerg	     ddp->idVendor, ddp->idProduct);
407238603Sjoerg
408238603Sjoerg      if (ddp->idVendor == vid && ddp->idProduct == pid)
409238603Sjoerg	doit(dev);
410238603Sjoerg    }
411238603Sjoerg
412238603Sjoerg  libusb20_be_free(be);
413238603Sjoerg  return 0;
414238603Sjoerg}
415