xref: /freebsd/share/examples/libusb20/bulk.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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