1 /*- 2 * SPDX-License-Identifier: Beerware 3 * 4 * ---------------------------------------------------------------------------- 5 * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp): 6 * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you 7 * can do whatever you want with this stuff. If we meet some day, and you think 8 * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch 9 * ---------------------------------------------------------------------------- 10 * 11 * $FreeBSD$ 12 */ 13 14 /* 15 * Simple demo program to illustrate the handling of FreeBSD's 16 * libusb20. 17 * 18 * Issues a bulk output, and then requests a bulk input. 19 */ 20 21 /* 22 * Examples: 23 * Just list all VID:PID pairs 24 * ./bulk 25 * 26 * Say "hello" to an Atmel JTAGICEmkII. 27 * ./bulk -o 2 -i 0x82 -v 0x03eb -p 0x2103 0x1b 0 0 1 0 0 0 0x0e 1 0xf3 0x97 28 * 29 * Return the INQUIRY data of an USB mass storage device. 30 * (It's best to have the umass(4) driver unloaded while doing such 31 * experiments, and perform a "usbconfig reset" for the device if it 32 * gets stuck.) 33 * ./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 34 */ 35 36 37 #include <limits.h> 38 #include <stdio.h> 39 #include <stdint.h> 40 #include <stdlib.h> 41 #include <sysexits.h> 42 #include <unistd.h> 43 44 #include <libusb20.h> 45 #include <libusb20_desc.h> 46 47 #include "util.h" 48 49 /* 50 * If you want to see the details of the internal datastructures 51 * in the debugger, unifdef the following. 52 */ 53 #ifdef DEBUG 54 # include <sys/queue.h> 55 # include "/usr/src/lib/libusb/libusb20_int.h" 56 #endif 57 58 #define BUFLEN 64 59 60 #define TIMEOUT 5000 /* 5 s */ 61 62 int in_ep, out_ep; /* endpoints */ 63 uint8_t out_buf[BUFLEN]; 64 uint16_t out_len; 65 66 static void 67 doit(struct libusb20_device *dev) 68 { 69 int rv; 70 71 /* 72 * Open the device, allocating memory for two possible (bulk or 73 * interrupt) transfers. 74 * 75 * If only control transfers are intended (via 76 * libusb20_dev_request_sync()), transfer_max can be given as 0. 77 */ 78 if ((rv = libusb20_dev_open(dev, 2)) != 0) 79 { 80 fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv)); 81 return; 82 } 83 84 /* 85 * If the device has more than one configuration, select the desired 86 * one here. 87 */ 88 if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0) 89 { 90 fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv)); 91 return; 92 } 93 94 /* 95 * Two transfers have been requested in libusb20_dev_open() above; 96 * obtain the corresponding transfer struct pointers. 97 */ 98 struct libusb20_transfer *xfr_out = libusb20_tr_get_pointer(dev, 0); 99 struct libusb20_transfer *xfr_in = libusb20_tr_get_pointer(dev, 1); 100 101 if (xfr_in == NULL || xfr_out == NULL) 102 { 103 fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv)); 104 return; 105 } 106 107 /* 108 * Open both transfers, the "out" one for the write endpoint, the 109 * "in" one for the read endpoint (ep | 0x80). 110 */ 111 if ((rv = libusb20_tr_open(xfr_out, 0, 1, out_ep)) != 0) 112 { 113 fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv)); 114 return; 115 } 116 if ((rv = libusb20_tr_open(xfr_in, 0, 1, in_ep)) != 0) 117 { 118 fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv)); 119 return; 120 } 121 122 uint8_t in_buf[BUFLEN]; 123 uint32_t rlen; 124 125 if (out_len > 0) 126 { 127 if ((rv = libusb20_tr_bulk_intr_sync(xfr_out, out_buf, out_len, &rlen, TIMEOUT)) 128 != 0) 129 { 130 fprintf(stderr, "libusb20_tr_bulk_intr_sync (OUT): %s\n", libusb20_strerror(rv)); 131 } 132 printf("sent %d bytes\n", rlen); 133 } 134 135 if ((rv = libusb20_tr_bulk_intr_sync(xfr_in, in_buf, BUFLEN, &rlen, TIMEOUT)) 136 != 0) 137 { 138 fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv)); 139 } 140 printf("received %d bytes\n", rlen); 141 if (rlen > 0) 142 print_formatted(in_buf, rlen); 143 144 libusb20_tr_close(xfr_out); 145 libusb20_tr_close(xfr_in); 146 147 libusb20_dev_close(dev); 148 } 149 150 static void 151 usage(void) 152 { 153 fprintf(stderr, 154 "Usage ./usb -i <IN_EP> -o <OUT_EP> -v <VID> -p <PID> [<outdata> ...\n]"); 155 exit(EX_USAGE); 156 } 157 158 int 159 main(int argc, char **argv) 160 { 161 unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */ 162 int c; 163 164 while ((c = getopt(argc, argv, "i:o:p:v:")) != -1) 165 switch (c) 166 { 167 case 'i': 168 in_ep = strtol(optarg, NULL, 0); 169 break; 170 171 case 'o': 172 out_ep = strtol(optarg, NULL, 0); 173 break; 174 175 case 'p': 176 pid = strtol(optarg, NULL, 0); 177 break; 178 179 case 'v': 180 vid = strtol(optarg, NULL, 0); 181 break; 182 183 default: 184 usage(); 185 break; 186 } 187 argc -= optind; 188 argv += optind; 189 190 if (vid != UINT_MAX || pid != UINT_MAX) 191 { 192 if (in_ep == 0 || out_ep == 0) 193 { 194 usage(); 195 } 196 if ((in_ep & 0x80) == 0) 197 { 198 fprintf(stderr, "IN_EP must have bit 7 set\n"); 199 return (EX_USAGE); 200 } 201 202 if (argc > 0) 203 { 204 for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--) 205 { 206 unsigned n = strtoul(argv[out_len], 0, 0); 207 if (n > 255) 208 fprintf(stderr, 209 "Warning: data #%d 0x%0x > 0xff, truncating\n", 210 out_len, n); 211 out_buf[out_len] = (uint8_t)n; 212 } 213 out_len++; 214 if (argc > 0) 215 fprintf(stderr, 216 "Data count exceeds maximum of %d, ignoring %d elements\n", 217 BUFLEN, optind); 218 } 219 } 220 221 struct libusb20_backend *be; 222 struct libusb20_device *dev; 223 224 if ((be = libusb20_be_alloc_default()) == NULL) 225 { 226 perror("libusb20_be_alloc()"); 227 return 1; 228 } 229 230 dev = NULL; 231 while ((dev = libusb20_be_device_foreach(be, dev)) != NULL) 232 { 233 struct LIBUSB20_DEVICE_DESC_DECODED *ddp = 234 libusb20_dev_get_device_desc(dev); 235 236 printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n", 237 libusb20_dev_get_desc(dev), 238 ddp->idVendor, ddp->idProduct); 239 240 if (ddp->idVendor == vid && ddp->idProduct == pid) 241 doit(dev); 242 } 243 244 libusb20_be_free(be); 245 return 0; 246 } 247