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