xref: /dflybsd-src/share/examples/libusb20/bulk.c (revision dacffe4a97e7da2372474d2659f622dca1897d40)
1*dacffe4aSSascha Wildner /* ----------------------------------------------------------------------------
2*dacffe4aSSascha Wildner  * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
3*dacffe4aSSascha Wildner  * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
4*dacffe4aSSascha Wildner  * can do whatever you want with this stuff. If we meet some day, and you think
5*dacffe4aSSascha Wildner  * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
6*dacffe4aSSascha Wildner  * ----------------------------------------------------------------------------
7*dacffe4aSSascha Wildner  *
8*dacffe4aSSascha Wildner  * $FreeBSD: head/share/examples/libusb20/bulk.c 257779 2013-11-07 07:22:51Z hselasky $
9*dacffe4aSSascha Wildner  */
10*dacffe4aSSascha Wildner 
11*dacffe4aSSascha Wildner /*
12*dacffe4aSSascha Wildner  * Simple demo program to illustrate the handling of FreeBSD's
13*dacffe4aSSascha Wildner  * libusb20.
14*dacffe4aSSascha Wildner  *
15*dacffe4aSSascha Wildner  * Issues a bulk output, and then requests a bulk input.
16*dacffe4aSSascha Wildner  */
17*dacffe4aSSascha Wildner 
18*dacffe4aSSascha Wildner /*
19*dacffe4aSSascha Wildner  * Examples:
20*dacffe4aSSascha Wildner  * Just list all VID:PID pairs
21*dacffe4aSSascha Wildner  * ./bulk
22*dacffe4aSSascha Wildner  *
23*dacffe4aSSascha Wildner  * Say "hello" to an Atmel JTAGICEmkII.
24*dacffe4aSSascha Wildner  * ./bulk -o 2 -i 0x82 -v 0x03eb -p 0x2103 0x1b 0 0 1 0 0 0 0x0e 1 0xf3 0x97
25*dacffe4aSSascha Wildner  *
26*dacffe4aSSascha Wildner  * Return the INQUIRY data of an USB mass storage device.
27*dacffe4aSSascha Wildner  * (It's best to have the umass(4) driver unloaded while doing such
28*dacffe4aSSascha Wildner  * experiments, and perform a "usbconfig reset" for the device if it
29*dacffe4aSSascha Wildner  * gets stuck.)
30*dacffe4aSSascha Wildner  * ./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
31*dacffe4aSSascha Wildner  */
32*dacffe4aSSascha Wildner 
33*dacffe4aSSascha Wildner 
34*dacffe4aSSascha Wildner #include <limits.h>
35*dacffe4aSSascha Wildner #include <stdio.h>
36*dacffe4aSSascha Wildner #include <stdint.h>
37*dacffe4aSSascha Wildner #include <stdlib.h>
38*dacffe4aSSascha Wildner #include <sysexits.h>
39*dacffe4aSSascha Wildner #include <unistd.h>
40*dacffe4aSSascha Wildner 
41*dacffe4aSSascha Wildner #include <libusb20.h>
42*dacffe4aSSascha Wildner #include <libusb20_desc.h>
43*dacffe4aSSascha Wildner 
44*dacffe4aSSascha Wildner #include "util.h"
45*dacffe4aSSascha Wildner 
46*dacffe4aSSascha Wildner /*
47*dacffe4aSSascha Wildner  * If you want to see the details of the internal datastructures
48*dacffe4aSSascha Wildner  * in the debugger, unifdef the following.
49*dacffe4aSSascha Wildner  */
50*dacffe4aSSascha Wildner #ifdef DEBUG
51*dacffe4aSSascha Wildner #  include <sys/queue.h>
52*dacffe4aSSascha Wildner #  include "/usr/src/lib/libusb/libusb20_int.h"
53*dacffe4aSSascha Wildner #endif
54*dacffe4aSSascha Wildner 
55*dacffe4aSSascha Wildner #define BUFLEN 64
56*dacffe4aSSascha Wildner 
57*dacffe4aSSascha Wildner #define TIMEOUT 5000 		/* 5 s */
58*dacffe4aSSascha Wildner 
59*dacffe4aSSascha Wildner int in_ep, out_ep;		/* endpoints */
60*dacffe4aSSascha Wildner uint8_t out_buf[BUFLEN];
61*dacffe4aSSascha Wildner uint16_t out_len;
62*dacffe4aSSascha Wildner 
63*dacffe4aSSascha Wildner static void
doit(struct libusb20_device * dev)64*dacffe4aSSascha Wildner doit(struct libusb20_device *dev)
65*dacffe4aSSascha Wildner {
66*dacffe4aSSascha Wildner   int rv;
67*dacffe4aSSascha Wildner 
68*dacffe4aSSascha Wildner   /*
69*dacffe4aSSascha Wildner    * Open the device, allocating memory for two possible (bulk or
70*dacffe4aSSascha Wildner    * interrupt) transfers.
71*dacffe4aSSascha Wildner    *
72*dacffe4aSSascha Wildner    * If only control transfers are intended (via
73*dacffe4aSSascha Wildner    * libusb20_dev_request_sync()), transfer_max can be given as 0.
74*dacffe4aSSascha Wildner    */
75*dacffe4aSSascha Wildner   if ((rv = libusb20_dev_open(dev, 2)) != 0)
76*dacffe4aSSascha Wildner     {
77*dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv));
78*dacffe4aSSascha Wildner       return;
79*dacffe4aSSascha Wildner     }
80*dacffe4aSSascha Wildner 
81*dacffe4aSSascha Wildner   /*
82*dacffe4aSSascha Wildner    * If the device has more than one configuration, select the desired
83*dacffe4aSSascha Wildner    * one here.
84*dacffe4aSSascha Wildner    */
85*dacffe4aSSascha Wildner   if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
86*dacffe4aSSascha Wildner     {
87*dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv));
88*dacffe4aSSascha Wildner       return;
89*dacffe4aSSascha Wildner     }
90*dacffe4aSSascha Wildner 
91*dacffe4aSSascha Wildner   /*
92*dacffe4aSSascha Wildner    * Two transfers have been requested in libusb20_dev_open() above;
93*dacffe4aSSascha Wildner    * obtain the corresponding transfer struct pointers.
94*dacffe4aSSascha Wildner    */
95*dacffe4aSSascha Wildner   struct libusb20_transfer *xfr_out = libusb20_tr_get_pointer(dev, 0);
96*dacffe4aSSascha Wildner   struct libusb20_transfer *xfr_in = libusb20_tr_get_pointer(dev, 1);
97*dacffe4aSSascha Wildner 
98*dacffe4aSSascha Wildner   if (xfr_in == NULL || xfr_out == NULL)
99*dacffe4aSSascha Wildner     {
100*dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv));
101*dacffe4aSSascha Wildner       return;
102*dacffe4aSSascha Wildner     }
103*dacffe4aSSascha Wildner 
104*dacffe4aSSascha Wildner   /*
105*dacffe4aSSascha Wildner    * Open both transfers, the "out" one for the write endpoint, the
106*dacffe4aSSascha Wildner    * "in" one for the read endpoint (ep | 0x80).
107*dacffe4aSSascha Wildner    */
108*dacffe4aSSascha Wildner   if ((rv = libusb20_tr_open(xfr_out, 0, 1, out_ep)) != 0)
109*dacffe4aSSascha Wildner     {
110*dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
111*dacffe4aSSascha Wildner       return;
112*dacffe4aSSascha Wildner     }
113*dacffe4aSSascha Wildner   if ((rv = libusb20_tr_open(xfr_in, 0, 1, in_ep)) != 0)
114*dacffe4aSSascha Wildner     {
115*dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
116*dacffe4aSSascha Wildner       return;
117*dacffe4aSSascha Wildner     }
118*dacffe4aSSascha Wildner 
119*dacffe4aSSascha Wildner   uint8_t in_buf[BUFLEN];
120*dacffe4aSSascha Wildner   uint32_t rlen;
121*dacffe4aSSascha Wildner 
122*dacffe4aSSascha Wildner   if (out_len > 0)
123*dacffe4aSSascha Wildner     {
124*dacffe4aSSascha Wildner       if ((rv = libusb20_tr_bulk_intr_sync(xfr_out, out_buf, out_len, &rlen, TIMEOUT))
125*dacffe4aSSascha Wildner 	  != 0)
126*dacffe4aSSascha Wildner 	{
127*dacffe4aSSascha Wildner 	  fprintf(stderr, "libusb20_tr_bulk_intr_sync (OUT): %s\n", libusb20_strerror(rv));
128*dacffe4aSSascha Wildner 	}
129*dacffe4aSSascha Wildner       printf("sent %d bytes\n", rlen);
130*dacffe4aSSascha Wildner     }
131*dacffe4aSSascha Wildner 
132*dacffe4aSSascha Wildner   if ((rv = libusb20_tr_bulk_intr_sync(xfr_in, in_buf, BUFLEN, &rlen, TIMEOUT))
133*dacffe4aSSascha Wildner       != 0)
134*dacffe4aSSascha Wildner     {
135*dacffe4aSSascha Wildner       fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv));
136*dacffe4aSSascha Wildner     }
137*dacffe4aSSascha Wildner       printf("received %d bytes\n", rlen);
138*dacffe4aSSascha Wildner       if (rlen > 0)
139*dacffe4aSSascha Wildner 	print_formatted(in_buf, rlen);
140*dacffe4aSSascha Wildner 
141*dacffe4aSSascha Wildner   libusb20_tr_close(xfr_out);
142*dacffe4aSSascha Wildner   libusb20_tr_close(xfr_in);
143*dacffe4aSSascha Wildner 
144*dacffe4aSSascha Wildner   libusb20_dev_close(dev);
145*dacffe4aSSascha Wildner }
146*dacffe4aSSascha Wildner 
147*dacffe4aSSascha Wildner static void
usage(void)148*dacffe4aSSascha Wildner usage(void)
149*dacffe4aSSascha Wildner {
150*dacffe4aSSascha Wildner   fprintf(stderr,
151*dacffe4aSSascha Wildner 	  "Usage ./usb -i <IN_EP> -o <OUT_EP> -v <VID> -p <PID> [<outdata> ...\n]");
152*dacffe4aSSascha Wildner   exit(EX_USAGE);
153*dacffe4aSSascha Wildner }
154*dacffe4aSSascha Wildner 
155*dacffe4aSSascha Wildner int
main(int argc,char ** argv)156*dacffe4aSSascha Wildner main(int argc, char **argv)
157*dacffe4aSSascha Wildner {
158*dacffe4aSSascha Wildner   unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
159*dacffe4aSSascha Wildner   int c;
160*dacffe4aSSascha Wildner 
161*dacffe4aSSascha Wildner   while ((c = getopt(argc, argv, "i:o:p:v:")) != -1)
162*dacffe4aSSascha Wildner     switch (c)
163*dacffe4aSSascha Wildner       {
164*dacffe4aSSascha Wildner       case 'i':
165*dacffe4aSSascha Wildner 	in_ep = strtol(optarg, NULL, 0);
166*dacffe4aSSascha Wildner 	break;
167*dacffe4aSSascha Wildner 
168*dacffe4aSSascha Wildner       case 'o':
169*dacffe4aSSascha Wildner 	out_ep = strtol(optarg, NULL, 0);
170*dacffe4aSSascha Wildner 	break;
171*dacffe4aSSascha Wildner 
172*dacffe4aSSascha Wildner       case 'p':
173*dacffe4aSSascha Wildner 	pid = strtol(optarg, NULL, 0);
174*dacffe4aSSascha Wildner 	break;
175*dacffe4aSSascha Wildner 
176*dacffe4aSSascha Wildner       case 'v':
177*dacffe4aSSascha Wildner 	vid = strtol(optarg, NULL, 0);
178*dacffe4aSSascha Wildner 	break;
179*dacffe4aSSascha Wildner 
180*dacffe4aSSascha Wildner       default:
181*dacffe4aSSascha Wildner 	usage();
182*dacffe4aSSascha Wildner 	break;
183*dacffe4aSSascha Wildner       }
184*dacffe4aSSascha Wildner   argc -= optind;
185*dacffe4aSSascha Wildner   argv += optind;
186*dacffe4aSSascha Wildner 
187*dacffe4aSSascha Wildner   if (vid != UINT_MAX || pid != UINT_MAX)
188*dacffe4aSSascha Wildner     {
189*dacffe4aSSascha Wildner       if (in_ep == 0 || out_ep == 0)
190*dacffe4aSSascha Wildner 	{
191*dacffe4aSSascha Wildner 	  usage();
192*dacffe4aSSascha Wildner 	}
193*dacffe4aSSascha Wildner       if ((in_ep & 0x80) == 0)
194*dacffe4aSSascha Wildner 	{
195*dacffe4aSSascha Wildner 	  fprintf(stderr, "IN_EP must have bit 7 set\n");
196*dacffe4aSSascha Wildner 	  return (EX_USAGE);
197*dacffe4aSSascha Wildner 	}
198*dacffe4aSSascha Wildner 
199*dacffe4aSSascha Wildner       if (argc > 0)
200*dacffe4aSSascha Wildner 	{
201*dacffe4aSSascha Wildner 	  for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
202*dacffe4aSSascha Wildner 	    {
203*dacffe4aSSascha Wildner 	      unsigned n = strtoul(argv[out_len], 0, 0);
204*dacffe4aSSascha Wildner 	      if (n > 255)
205*dacffe4aSSascha Wildner 		fprintf(stderr,
206*dacffe4aSSascha Wildner 			"Warning: data #%d 0x%0x > 0xff, truncating\n",
207*dacffe4aSSascha Wildner 			out_len, n);
208*dacffe4aSSascha Wildner 	      out_buf[out_len] = (uint8_t)n;
209*dacffe4aSSascha Wildner 	    }
210*dacffe4aSSascha Wildner 	  out_len++;
211*dacffe4aSSascha Wildner 	  if (argc > 0)
212*dacffe4aSSascha Wildner 	    fprintf(stderr,
213*dacffe4aSSascha Wildner 		    "Data count exceeds maximum of %d, ignoring %d elements\n",
214*dacffe4aSSascha Wildner 		    BUFLEN, optind);
215*dacffe4aSSascha Wildner 	}
216*dacffe4aSSascha Wildner     }
217*dacffe4aSSascha Wildner 
218*dacffe4aSSascha Wildner   struct libusb20_backend *be;
219*dacffe4aSSascha Wildner   struct libusb20_device *dev;
220*dacffe4aSSascha Wildner 
221*dacffe4aSSascha Wildner   if ((be = libusb20_be_alloc_default()) == NULL)
222*dacffe4aSSascha Wildner     {
223*dacffe4aSSascha Wildner       perror("libusb20_be_alloc()");
224*dacffe4aSSascha Wildner       return 1;
225*dacffe4aSSascha Wildner     }
226*dacffe4aSSascha Wildner 
227*dacffe4aSSascha Wildner   dev = NULL;
228*dacffe4aSSascha Wildner   while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
229*dacffe4aSSascha Wildner     {
230*dacffe4aSSascha Wildner       struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
231*dacffe4aSSascha Wildner       libusb20_dev_get_device_desc(dev);
232*dacffe4aSSascha Wildner 
233*dacffe4aSSascha Wildner       printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
234*dacffe4aSSascha Wildner 	     libusb20_dev_get_desc(dev),
235*dacffe4aSSascha Wildner 	     ddp->idVendor, ddp->idProduct);
236*dacffe4aSSascha Wildner 
237*dacffe4aSSascha Wildner       if (ddp->idVendor == vid && ddp->idProduct == pid)
238*dacffe4aSSascha Wildner 	doit(dev);
239*dacffe4aSSascha Wildner     }
240*dacffe4aSSascha Wildner 
241*dacffe4aSSascha Wildner   libusb20_be_free(be);
242*dacffe4aSSascha Wildner   return 0;
243*dacffe4aSSascha Wildner }
244