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