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