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