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