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$
9238603Sjoerg */
10238603Sjoerg
11238603Sjoerg/*
12238603Sjoerg * Simple demo program to illustrate the handling of FreeBSD's
13238603Sjoerg * libusb20.
14238603Sjoerg *
15238603Sjoerg * Issues a bulk output, and then requests a bulk input.
16238603Sjoerg */
17238603Sjoerg
18238603Sjoerg/*
19238603Sjoerg * Examples:
20238603Sjoerg * Just list all VID:PID pairs
21238603Sjoerg * ./bulk
22238603Sjoerg *
23238603Sjoerg * Say "hello" to an Atmel JTAGICEmkII.
24238603Sjoerg * ./bulk -o 2 -i 0x82 -v 0x03eb -p 0x2103 0x1b 0 0 1 0 0 0 0x0e 1 0xf3 0x97
25238603Sjoerg *
26238603Sjoerg * Return the INQUIRY data of an USB mass storage device.
27238603Sjoerg * (It's best to have the umass(4) driver unloaded while doing such
28238603Sjoerg * experiments, and perform a "usbconfig reset" for the device if it
29238603Sjoerg * gets stuck.)
30238603Sjoerg * ./bulk -v 0x5e3 -p 0x723 -i 0x81 -o 2 0x55 0x53 0x42 0x43 1 2 3 4 31 12 0x80 0x24 0 0 0 0x12 0 0 0 36 0 0 0 0 0 0 0 0 0 0
31238603Sjoerg */
32238603Sjoerg
33238603Sjoerg
34238603Sjoerg#include <limits.h>
35238603Sjoerg#include <stdio.h>
36238603Sjoerg#include <stdint.h>
37238603Sjoerg#include <stdlib.h>
38238603Sjoerg#include <sysexits.h>
39238603Sjoerg#include <unistd.h>
40238603Sjoerg
41238603Sjoerg#include <libusb20.h>
42238603Sjoerg#include <libusb20_desc.h>
43238603Sjoerg
44269879Semaste#include "util.h"
45238603Sjoerg
46238603Sjoerg/*
47238603Sjoerg * If you want to see the details of the internal datastructures
48238603Sjoerg * in the debugger, unifdef the following.
49238603Sjoerg */
50238603Sjoerg#ifdef DEBUG
51238603Sjoerg#  include <sys/queue.h>
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 in_ep, out_ep;		/* endpoints */
60238603Sjoerguint8_t out_buf[BUFLEN];
61238603Sjoerguint16_t out_len;
62238603Sjoerg
63238603Sjoergstatic void
64238603Sjoergdoit(struct libusb20_device *dev)
65238603Sjoerg{
66238603Sjoerg  int rv;
67238603Sjoerg
68238603Sjoerg  /*
69238603Sjoerg   * Open the device, allocating memory for two possible (bulk or
70238603Sjoerg   * interrupt) transfers.
71238603Sjoerg   *
72238603Sjoerg   * If only control transfers are intended (via
73238603Sjoerg   * libusb20_dev_request_sync()), transfer_max can be given as 0.
74238603Sjoerg   */
75238603Sjoerg  if ((rv = libusb20_dev_open(dev, 2)) != 0)
76238603Sjoerg    {
77269879Semaste      fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv));
78238603Sjoerg      return;
79238603Sjoerg    }
80238603Sjoerg
81238603Sjoerg  /*
82238603Sjoerg   * If the device has more than one configuration, select the desired
83238603Sjoerg   * one here.
84238603Sjoerg   */
85238603Sjoerg  if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
86238603Sjoerg    {
87269879Semaste      fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv));
88238603Sjoerg      return;
89238603Sjoerg    }
90238603Sjoerg
91238603Sjoerg  /*
92238603Sjoerg   * Two transfers have been requested in libusb20_dev_open() above;
93238603Sjoerg   * obtain the corresponding transfer struct pointers.
94238603Sjoerg   */
95238603Sjoerg  struct libusb20_transfer *xfr_out = libusb20_tr_get_pointer(dev, 0);
96238603Sjoerg  struct libusb20_transfer *xfr_in = libusb20_tr_get_pointer(dev, 1);
97238603Sjoerg
98238603Sjoerg  if (xfr_in == NULL || xfr_out == NULL)
99238603Sjoerg    {
100269879Semaste      fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv));
101238603Sjoerg      return;
102238603Sjoerg    }
103238603Sjoerg
104238603Sjoerg  /*
105238603Sjoerg   * Open both transfers, the "out" one for the write endpoint, the
106238603Sjoerg   * "in" one for the read endpoint (ep | 0x80).
107238603Sjoerg   */
108238603Sjoerg  if ((rv = libusb20_tr_open(xfr_out, 0, 1, out_ep)) != 0)
109238603Sjoerg    {
110269879Semaste      fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
111238603Sjoerg      return;
112238603Sjoerg    }
113238603Sjoerg  if ((rv = libusb20_tr_open(xfr_in, 0, 1, in_ep)) != 0)
114238603Sjoerg    {
115269879Semaste      fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
116238603Sjoerg      return;
117238603Sjoerg    }
118238603Sjoerg
119238603Sjoerg  uint8_t in_buf[BUFLEN];
120238603Sjoerg  uint32_t rlen;
121238603Sjoerg
122238603Sjoerg  if (out_len > 0)
123238603Sjoerg    {
124238603Sjoerg      if ((rv = libusb20_tr_bulk_intr_sync(xfr_out, out_buf, out_len, &rlen, TIMEOUT))
125238603Sjoerg	  != 0)
126238603Sjoerg	{
127269879Semaste	  fprintf(stderr, "libusb20_tr_bulk_intr_sync (OUT): %s\n", libusb20_strerror(rv));
128238603Sjoerg	}
129238603Sjoerg      printf("sent %d bytes\n", rlen);
130238603Sjoerg    }
131238603Sjoerg
132238603Sjoerg  if ((rv = libusb20_tr_bulk_intr_sync(xfr_in, in_buf, BUFLEN, &rlen, TIMEOUT))
133238603Sjoerg      != 0)
134238603Sjoerg    {
135269879Semaste      fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv));
136238603Sjoerg    }
137238603Sjoerg      printf("received %d bytes\n", rlen);
138238603Sjoerg      if (rlen > 0)
139238603Sjoerg	print_formatted(in_buf, rlen);
140238603Sjoerg
141238603Sjoerg  libusb20_tr_close(xfr_out);
142238603Sjoerg  libusb20_tr_close(xfr_in);
143238603Sjoerg
144238603Sjoerg  libusb20_dev_close(dev);
145238603Sjoerg}
146238603Sjoerg
147238603Sjoergstatic void
148238603Sjoergusage(void)
149238603Sjoerg{
150238603Sjoerg  fprintf(stderr,
151238603Sjoerg	  "Usage ./usb -i <IN_EP> -o <OUT_EP> -v <VID> -p <PID> [<outdata> ...\n]");
152238603Sjoerg  exit(EX_USAGE);
153238603Sjoerg}
154238603Sjoerg
155238603Sjoergint
156238603Sjoergmain(int argc, char **argv)
157238603Sjoerg{
158238603Sjoerg  unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
159238603Sjoerg  int c;
160238603Sjoerg
161238603Sjoerg  while ((c = getopt(argc, argv, "i:o:p:v:")) != -1)
162238603Sjoerg    switch (c)
163238603Sjoerg      {
164238603Sjoerg      case 'i':
165238603Sjoerg	in_ep = strtol(optarg, NULL, 0);
166238603Sjoerg	break;
167238603Sjoerg
168238603Sjoerg      case 'o':
169238603Sjoerg	out_ep = strtol(optarg, NULL, 0);
170238603Sjoerg	break;
171238603Sjoerg
172238603Sjoerg      case 'p':
173238603Sjoerg	pid = strtol(optarg, NULL, 0);
174238603Sjoerg	break;
175238603Sjoerg
176238603Sjoerg      case 'v':
177238603Sjoerg	vid = strtol(optarg, NULL, 0);
178238603Sjoerg	break;
179238603Sjoerg
180238603Sjoerg      default:
181238603Sjoerg	usage();
182238603Sjoerg	break;
183238603Sjoerg      }
184238603Sjoerg  argc -= optind;
185238603Sjoerg  argv += optind;
186238603Sjoerg
187238603Sjoerg  if (vid != UINT_MAX || pid != UINT_MAX)
188238603Sjoerg    {
189238603Sjoerg      if (in_ep == 0 || out_ep == 0)
190238603Sjoerg	{
191238603Sjoerg	  usage();
192238603Sjoerg	}
193238603Sjoerg      if ((in_ep & 0x80) == 0)
194238603Sjoerg	{
195238603Sjoerg	  fprintf(stderr, "IN_EP must have bit 7 set\n");
196238603Sjoerg	  return (EX_USAGE);
197238603Sjoerg	}
198238603Sjoerg
199238603Sjoerg      if (argc > 0)
200238603Sjoerg	{
201238603Sjoerg	  for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
202238603Sjoerg	    {
203238603Sjoerg	      unsigned n = strtoul(argv[out_len], 0, 0);
204238603Sjoerg	      if (n > 255)
205238603Sjoerg		fprintf(stderr,
206238603Sjoerg			"Warning: data #%d 0x%0x > 0xff, truncating\n",
207238603Sjoerg			out_len, n);
208238603Sjoerg	      out_buf[out_len] = (uint8_t)n;
209238603Sjoerg	    }
210238603Sjoerg	  out_len++;
211238603Sjoerg	  if (argc > 0)
212238603Sjoerg	    fprintf(stderr,
213238603Sjoerg		    "Data count exceeds maximum of %d, ignoring %d elements\n",
214238603Sjoerg		    BUFLEN, optind);
215238603Sjoerg	}
216238603Sjoerg    }
217238603Sjoerg
218238603Sjoerg  struct libusb20_backend *be;
219238603Sjoerg  struct libusb20_device *dev;
220238603Sjoerg
221238603Sjoerg  if ((be = libusb20_be_alloc_default()) == NULL)
222238603Sjoerg    {
223238603Sjoerg      perror("libusb20_be_alloc()");
224238603Sjoerg      return 1;
225238603Sjoerg    }
226238603Sjoerg
227238603Sjoerg  dev = NULL;
228238603Sjoerg  while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
229238603Sjoerg    {
230238603Sjoerg      struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
231238603Sjoerg      libusb20_dev_get_device_desc(dev);
232238603Sjoerg
233238603Sjoerg      printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
234238603Sjoerg	     libusb20_dev_get_desc(dev),
235238603Sjoerg	     ddp->idVendor, ddp->idProduct);
236238603Sjoerg
237238603Sjoerg      if (ddp->idVendor == vid && ddp->idProduct == pid)
238238603Sjoerg	doit(dev);
239238603Sjoerg    }
240238603Sjoerg
241238603Sjoerg  libusb20_be_free(be);
242238603Sjoerg  return 0;
243238603Sjoerg}
244