1*64de3fddSPedro F. Giffuni /*-
2*64de3fddSPedro F. Giffuni * SPDX-License-Identifier: Beerware
3*64de3fddSPedro F. Giffuni *
4*64de3fddSPedro F. Giffuni * ----------------------------------------------------------------------------
53b9676efSJoerg Wunsch * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
63b9676efSJoerg Wunsch * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
73b9676efSJoerg Wunsch * can do whatever you want with this stuff. If we meet some day, and you think
83b9676efSJoerg Wunsch * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
93b9676efSJoerg Wunsch * ----------------------------------------------------------------------------
103b9676efSJoerg Wunsch */
113b9676efSJoerg Wunsch
123b9676efSJoerg Wunsch /*
133b9676efSJoerg Wunsch * Simple demo program to illustrate the handling of FreeBSD's
143b9676efSJoerg Wunsch * libusb20.
153b9676efSJoerg Wunsch *
163b9676efSJoerg Wunsch * Issues a bulk output, and then requests a bulk input.
173b9676efSJoerg Wunsch */
183b9676efSJoerg Wunsch
193b9676efSJoerg Wunsch /*
203b9676efSJoerg Wunsch * Examples:
213b9676efSJoerg Wunsch * Just list all VID:PID pairs
223b9676efSJoerg Wunsch * ./bulk
233b9676efSJoerg Wunsch *
243b9676efSJoerg Wunsch * Say "hello" to an Atmel JTAGICEmkII.
253b9676efSJoerg Wunsch * ./bulk -o 2 -i 0x82 -v 0x03eb -p 0x2103 0x1b 0 0 1 0 0 0 0x0e 1 0xf3 0x97
263b9676efSJoerg Wunsch *
273b9676efSJoerg Wunsch * Return the INQUIRY data of an USB mass storage device.
283b9676efSJoerg Wunsch * (It's best to have the umass(4) driver unloaded while doing such
293b9676efSJoerg Wunsch * experiments, and perform a "usbconfig reset" for the device if it
303b9676efSJoerg Wunsch * gets stuck.)
313b9676efSJoerg Wunsch * ./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
323b9676efSJoerg Wunsch */
333b9676efSJoerg Wunsch
343b9676efSJoerg Wunsch
353b9676efSJoerg Wunsch #include <limits.h>
363b9676efSJoerg Wunsch #include <stdio.h>
373b9676efSJoerg Wunsch #include <stdint.h>
383b9676efSJoerg Wunsch #include <stdlib.h>
393b9676efSJoerg Wunsch #include <sysexits.h>
403b9676efSJoerg Wunsch #include <unistd.h>
413b9676efSJoerg Wunsch
423b9676efSJoerg Wunsch #include <libusb20.h>
433b9676efSJoerg Wunsch #include <libusb20_desc.h>
443b9676efSJoerg Wunsch
452578c12eSHans Petter Selasky #include "util.h"
463b9676efSJoerg Wunsch
473b9676efSJoerg Wunsch /*
483b9676efSJoerg Wunsch * If you want to see the details of the internal datastructures
493b9676efSJoerg Wunsch * in the debugger, unifdef the following.
503b9676efSJoerg Wunsch */
513b9676efSJoerg Wunsch #ifdef DEBUG
523b9676efSJoerg Wunsch # include <sys/queue.h>
533b9676efSJoerg Wunsch # include "/usr/src/lib/libusb/libusb20_int.h"
543b9676efSJoerg Wunsch #endif
553b9676efSJoerg Wunsch
563b9676efSJoerg Wunsch #define BUFLEN 64
573b9676efSJoerg Wunsch
583b9676efSJoerg Wunsch #define TIMEOUT 5000 /* 5 s */
593b9676efSJoerg Wunsch
603b9676efSJoerg Wunsch int in_ep, out_ep; /* endpoints */
613b9676efSJoerg Wunsch uint8_t out_buf[BUFLEN];
623b9676efSJoerg Wunsch uint16_t out_len;
633b9676efSJoerg Wunsch
643b9676efSJoerg Wunsch static void
doit(struct libusb20_device * dev)653b9676efSJoerg Wunsch doit(struct libusb20_device *dev)
663b9676efSJoerg Wunsch {
673b9676efSJoerg Wunsch int rv;
683b9676efSJoerg Wunsch
693b9676efSJoerg Wunsch /*
703b9676efSJoerg Wunsch * Open the device, allocating memory for two possible (bulk or
713b9676efSJoerg Wunsch * interrupt) transfers.
723b9676efSJoerg Wunsch *
733b9676efSJoerg Wunsch * If only control transfers are intended (via
743b9676efSJoerg Wunsch * libusb20_dev_request_sync()), transfer_max can be given as 0.
753b9676efSJoerg Wunsch */
763b9676efSJoerg Wunsch if ((rv = libusb20_dev_open(dev, 2)) != 0)
773b9676efSJoerg Wunsch {
782578c12eSHans Petter Selasky fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv));
793b9676efSJoerg Wunsch return;
803b9676efSJoerg Wunsch }
813b9676efSJoerg Wunsch
823b9676efSJoerg Wunsch /*
833b9676efSJoerg Wunsch * If the device has more than one configuration, select the desired
843b9676efSJoerg Wunsch * one here.
853b9676efSJoerg Wunsch */
863b9676efSJoerg Wunsch if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
873b9676efSJoerg Wunsch {
882578c12eSHans Petter Selasky fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv));
893b9676efSJoerg Wunsch return;
903b9676efSJoerg Wunsch }
913b9676efSJoerg Wunsch
923b9676efSJoerg Wunsch /*
933b9676efSJoerg Wunsch * Two transfers have been requested in libusb20_dev_open() above;
943b9676efSJoerg Wunsch * obtain the corresponding transfer struct pointers.
953b9676efSJoerg Wunsch */
963b9676efSJoerg Wunsch struct libusb20_transfer *xfr_out = libusb20_tr_get_pointer(dev, 0);
973b9676efSJoerg Wunsch struct libusb20_transfer *xfr_in = libusb20_tr_get_pointer(dev, 1);
983b9676efSJoerg Wunsch
993b9676efSJoerg Wunsch if (xfr_in == NULL || xfr_out == NULL)
1003b9676efSJoerg Wunsch {
1012578c12eSHans Petter Selasky fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv));
1023b9676efSJoerg Wunsch return;
1033b9676efSJoerg Wunsch }
1043b9676efSJoerg Wunsch
1053b9676efSJoerg Wunsch /*
1063b9676efSJoerg Wunsch * Open both transfers, the "out" one for the write endpoint, the
1073b9676efSJoerg Wunsch * "in" one for the read endpoint (ep | 0x80).
1083b9676efSJoerg Wunsch */
1093b9676efSJoerg Wunsch if ((rv = libusb20_tr_open(xfr_out, 0, 1, out_ep)) != 0)
1103b9676efSJoerg Wunsch {
1112578c12eSHans Petter Selasky fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
1123b9676efSJoerg Wunsch return;
1133b9676efSJoerg Wunsch }
1143b9676efSJoerg Wunsch if ((rv = libusb20_tr_open(xfr_in, 0, 1, in_ep)) != 0)
1153b9676efSJoerg Wunsch {
1162578c12eSHans Petter Selasky fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
1173b9676efSJoerg Wunsch return;
1183b9676efSJoerg Wunsch }
1193b9676efSJoerg Wunsch
1203b9676efSJoerg Wunsch uint8_t in_buf[BUFLEN];
1213b9676efSJoerg Wunsch uint32_t rlen;
1223b9676efSJoerg Wunsch
1233b9676efSJoerg Wunsch if (out_len > 0)
1243b9676efSJoerg Wunsch {
1253b9676efSJoerg Wunsch if ((rv = libusb20_tr_bulk_intr_sync(xfr_out, out_buf, out_len, &rlen, TIMEOUT))
1263b9676efSJoerg Wunsch != 0)
1273b9676efSJoerg Wunsch {
1282578c12eSHans Petter Selasky fprintf(stderr, "libusb20_tr_bulk_intr_sync (OUT): %s\n", libusb20_strerror(rv));
1293b9676efSJoerg Wunsch }
1303b9676efSJoerg Wunsch printf("sent %d bytes\n", rlen);
1313b9676efSJoerg Wunsch }
1323b9676efSJoerg Wunsch
1333b9676efSJoerg Wunsch if ((rv = libusb20_tr_bulk_intr_sync(xfr_in, in_buf, BUFLEN, &rlen, TIMEOUT))
1343b9676efSJoerg Wunsch != 0)
1353b9676efSJoerg Wunsch {
1362578c12eSHans Petter Selasky fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv));
1373b9676efSJoerg Wunsch }
1383b9676efSJoerg Wunsch printf("received %d bytes\n", rlen);
1393b9676efSJoerg Wunsch if (rlen > 0)
1403b9676efSJoerg Wunsch print_formatted(in_buf, rlen);
1413b9676efSJoerg Wunsch
1423b9676efSJoerg Wunsch libusb20_tr_close(xfr_out);
1433b9676efSJoerg Wunsch libusb20_tr_close(xfr_in);
1443b9676efSJoerg Wunsch
1453b9676efSJoerg Wunsch libusb20_dev_close(dev);
1463b9676efSJoerg Wunsch }
1473b9676efSJoerg Wunsch
1483b9676efSJoerg Wunsch static void
usage(void)1493b9676efSJoerg Wunsch usage(void)
1503b9676efSJoerg Wunsch {
1513b9676efSJoerg Wunsch fprintf(stderr,
1523b9676efSJoerg Wunsch "Usage ./usb -i <IN_EP> -o <OUT_EP> -v <VID> -p <PID> [<outdata> ...\n]");
1533b9676efSJoerg Wunsch exit(EX_USAGE);
1543b9676efSJoerg Wunsch }
1553b9676efSJoerg Wunsch
1563b9676efSJoerg Wunsch int
main(int argc,char ** argv)1573b9676efSJoerg Wunsch main(int argc, char **argv)
1583b9676efSJoerg Wunsch {
1593b9676efSJoerg Wunsch unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
1603b9676efSJoerg Wunsch int c;
1613b9676efSJoerg Wunsch
1623b9676efSJoerg Wunsch while ((c = getopt(argc, argv, "i:o:p:v:")) != -1)
1633b9676efSJoerg Wunsch switch (c)
1643b9676efSJoerg Wunsch {
1653b9676efSJoerg Wunsch case 'i':
1663b9676efSJoerg Wunsch in_ep = strtol(optarg, NULL, 0);
1673b9676efSJoerg Wunsch break;
1683b9676efSJoerg Wunsch
1693b9676efSJoerg Wunsch case 'o':
1703b9676efSJoerg Wunsch out_ep = strtol(optarg, NULL, 0);
1713b9676efSJoerg Wunsch break;
1723b9676efSJoerg Wunsch
1733b9676efSJoerg Wunsch case 'p':
1743b9676efSJoerg Wunsch pid = strtol(optarg, NULL, 0);
1753b9676efSJoerg Wunsch break;
1763b9676efSJoerg Wunsch
1773b9676efSJoerg Wunsch case 'v':
1783b9676efSJoerg Wunsch vid = strtol(optarg, NULL, 0);
1793b9676efSJoerg Wunsch break;
1803b9676efSJoerg Wunsch
1813b9676efSJoerg Wunsch default:
1823b9676efSJoerg Wunsch usage();
1833b9676efSJoerg Wunsch break;
1843b9676efSJoerg Wunsch }
1853b9676efSJoerg Wunsch argc -= optind;
1863b9676efSJoerg Wunsch argv += optind;
1873b9676efSJoerg Wunsch
1883b9676efSJoerg Wunsch if (vid != UINT_MAX || pid != UINT_MAX)
1893b9676efSJoerg Wunsch {
1903b9676efSJoerg Wunsch if (in_ep == 0 || out_ep == 0)
1913b9676efSJoerg Wunsch {
1923b9676efSJoerg Wunsch usage();
1933b9676efSJoerg Wunsch }
1943b9676efSJoerg Wunsch if ((in_ep & 0x80) == 0)
1953b9676efSJoerg Wunsch {
1963b9676efSJoerg Wunsch fprintf(stderr, "IN_EP must have bit 7 set\n");
1973b9676efSJoerg Wunsch return (EX_USAGE);
1983b9676efSJoerg Wunsch }
1993b9676efSJoerg Wunsch
2003b9676efSJoerg Wunsch if (argc > 0)
2013b9676efSJoerg Wunsch {
2023b9676efSJoerg Wunsch for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
2033b9676efSJoerg Wunsch {
2043b9676efSJoerg Wunsch unsigned n = strtoul(argv[out_len], 0, 0);
2053b9676efSJoerg Wunsch if (n > 255)
2063b9676efSJoerg Wunsch fprintf(stderr,
2073b9676efSJoerg Wunsch "Warning: data #%d 0x%0x > 0xff, truncating\n",
2083b9676efSJoerg Wunsch out_len, n);
2093b9676efSJoerg Wunsch out_buf[out_len] = (uint8_t)n;
2103b9676efSJoerg Wunsch }
2113b9676efSJoerg Wunsch out_len++;
2123b9676efSJoerg Wunsch if (argc > 0)
2133b9676efSJoerg Wunsch fprintf(stderr,
2143b9676efSJoerg Wunsch "Data count exceeds maximum of %d, ignoring %d elements\n",
2153b9676efSJoerg Wunsch BUFLEN, optind);
2163b9676efSJoerg Wunsch }
2173b9676efSJoerg Wunsch }
2183b9676efSJoerg Wunsch
2193b9676efSJoerg Wunsch struct libusb20_backend *be;
2203b9676efSJoerg Wunsch struct libusb20_device *dev;
2213b9676efSJoerg Wunsch
2223b9676efSJoerg Wunsch if ((be = libusb20_be_alloc_default()) == NULL)
2233b9676efSJoerg Wunsch {
2243b9676efSJoerg Wunsch perror("libusb20_be_alloc()");
2253b9676efSJoerg Wunsch return 1;
2263b9676efSJoerg Wunsch }
2273b9676efSJoerg Wunsch
2283b9676efSJoerg Wunsch dev = NULL;
2293b9676efSJoerg Wunsch while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
2303b9676efSJoerg Wunsch {
2313b9676efSJoerg Wunsch struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
2323b9676efSJoerg Wunsch libusb20_dev_get_device_desc(dev);
2333b9676efSJoerg Wunsch
2343b9676efSJoerg Wunsch printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
2353b9676efSJoerg Wunsch libusb20_dev_get_desc(dev),
2363b9676efSJoerg Wunsch ddp->idVendor, ddp->idProduct);
2373b9676efSJoerg Wunsch
2383b9676efSJoerg Wunsch if (ddp->idVendor == vid && ddp->idProduct == pid)
2393b9676efSJoerg Wunsch doit(dev);
2403b9676efSJoerg Wunsch }
2413b9676efSJoerg Wunsch
2423b9676efSJoerg Wunsch libusb20_be_free(be);
2433b9676efSJoerg Wunsch return 0;
2443b9676efSJoerg Wunsch }
245