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