1238603Sjoerg/* ---------------------------------------------------------------------------- 2238603Sjoerg * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp): 3238603Sjoerg * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you 4238603Sjoerg * can do whatever you want with this stuff. If we meet some day, and you think 5238603Sjoerg * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch 6238603Sjoerg * ---------------------------------------------------------------------------- 7238603Sjoerg * 8238603Sjoerg * $FreeBSD$ 9238603Sjoerg */ 10238603Sjoerg 11238603Sjoerg/* 12238603Sjoerg * Simple demo program to illustrate the handling of FreeBSD's 13238603Sjoerg * libusb20. 14238603Sjoerg */ 15238603Sjoerg 16238603Sjoerg/* 17238603Sjoerg * Examples: 18238603Sjoerg * Just list all VID:PID pairs 19238603Sjoerg * ./control 20238603Sjoerg * 21238603Sjoerg * Standard device request GET_STATUS, report two bytes of status 22238603Sjoerg * (bit 0 in the first byte returned is the "self powered" bit) 23238603Sjoerg * ./control -v 0x3eb -p 0x2103 in std dev get_status 0 0 2 24238603Sjoerg * 25238603Sjoerg * Request input reports through the interrupt pipe from a mouse 26238603Sjoerg * device (move the mouse around after issuing the command): 27238603Sjoerg * ./control -v 0x093a -p 0x2516 -i 0x81 28238603Sjoerg * 29238603Sjoerg */ 30238603Sjoerg 31238603Sjoerg 32238603Sjoerg#include <limits.h> 33238603Sjoerg#include <stdbool.h> 34238603Sjoerg#include <stdio.h> 35238603Sjoerg#include <stdint.h> 36238603Sjoerg#include <stdlib.h> 37238603Sjoerg#include <sysexits.h> 38238603Sjoerg#include <unistd.h> 39269879Semaste#include <string.h> 40238603Sjoerg 41238603Sjoerg#include <libusb20.h> 42238603Sjoerg#include <libusb20_desc.h> 43238603Sjoerg 44238603Sjoerg#include <sys/queue.h> 45238603Sjoerg 46269879Semaste#include "util.h" 47269879Semaste 48238603Sjoerg/* 49238603Sjoerg * If you want to see the details of the internal datastructures 50238603Sjoerg * in the debugger, unifdef the following. 51238603Sjoerg */ 52238603Sjoerg#ifdef DEBUG 53238603Sjoerg# include "/usr/src/lib/libusb/libusb20_int.h" 54238603Sjoerg#endif 55238603Sjoerg 56238603Sjoerg#define BUFLEN 64 57238603Sjoerg 58238603Sjoerg#define TIMEOUT 5000 /* 5 s */ 59238603Sjoerg 60238603Sjoergint intr_ep; /* endpoints */ 61238603Sjoergstruct LIBUSB20_CONTROL_SETUP_DECODED setup; 62238603Sjoerg 63238603Sjoerguint8_t out_buf[BUFLEN]; 64238603Sjoerguint16_t out_len; 65238603Sjoerg 66238603Sjoergbool do_request; 67238603Sjoerg 68238603Sjoergstatic void 69238603Sjoergdoit(struct libusb20_device *dev) 70238603Sjoerg{ 71238603Sjoerg int rv; 72238603Sjoerg 73238603Sjoerg if (do_request) 74238603Sjoerg printf("doit(): bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\n", 75238603Sjoerg setup.bmRequestType, 76238603Sjoerg setup.bRequest, 77238603Sjoerg setup.wValue, 78238603Sjoerg setup.wIndex, 79238603Sjoerg setup.wLength); 80238603Sjoerg 81238603Sjoerg /* 82238603Sjoerg * Open the device, allocating memory for two possible (bulk or 83238603Sjoerg * interrupt) transfers. 84238603Sjoerg * 85238603Sjoerg * If only control transfers are intended (via 86238603Sjoerg * libusb20_dev_request_sync()), transfer_max can be given as 0. 87238603Sjoerg */ 88238603Sjoerg if ((rv = libusb20_dev_open(dev, 1)) != 0) 89238603Sjoerg { 90269879Semaste fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv)); 91238603Sjoerg return; 92238603Sjoerg } 93238603Sjoerg 94238603Sjoerg /* 95238603Sjoerg * If the device has more than one configuration, select the desired 96238603Sjoerg * one here. 97238603Sjoerg */ 98238603Sjoerg if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0) 99238603Sjoerg { 100269879Semaste fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv)); 101238603Sjoerg return; 102238603Sjoerg } 103238603Sjoerg 104238603Sjoerg uint8_t *data = 0; 105238603Sjoerg uint16_t actlen; 106238603Sjoerg 107238603Sjoerg if ((setup.bmRequestType & 0x80) != 0) 108238603Sjoerg { 109238603Sjoerg /* this is an IN request, allocate a buffer */ 110238603Sjoerg data = malloc(setup.wLength); 111238603Sjoerg if (data == 0) 112238603Sjoerg { 113238603Sjoerg fprintf(stderr, 114238603Sjoerg "Out of memory allocating %u bytes of reply buffer\n", 115238603Sjoerg setup.wLength); 116238603Sjoerg return; 117238603Sjoerg } 118238603Sjoerg } 119238603Sjoerg else 120238603Sjoerg data = out_buf; 121238603Sjoerg 122238603Sjoerg if (do_request) 123238603Sjoerg { 124238603Sjoerg if ((rv = libusb20_dev_request_sync(dev, &setup, data, 125238603Sjoerg &actlen, 126238603Sjoerg TIMEOUT, 127238603Sjoerg 0 /* flags */)) != 0) 128238603Sjoerg { 129238603Sjoerg fprintf(stderr, 130269879Semaste "libusb20_dev_request_sync: %s\n", libusb20_strerror(rv)); 131238603Sjoerg } 132238603Sjoerg printf("sent %d bytes\n", actlen); 133238603Sjoerg if ((setup.bmRequestType & 0x80) != 0) 134238603Sjoerg { 135238603Sjoerg print_formatted(data, (uint32_t)setup.wLength); 136238603Sjoerg free(data); 137238603Sjoerg } 138238603Sjoerg } 139238603Sjoerg 140238603Sjoerg if (intr_ep != 0) 141238603Sjoerg { 142238603Sjoerg /* 143238603Sjoerg * One transfer has been requested in libusb20_dev_open() above; 144238603Sjoerg * obtain the corresponding transfer struct pointer. 145238603Sjoerg */ 146238603Sjoerg struct libusb20_transfer *xfr_intr = libusb20_tr_get_pointer(dev, 0); 147238603Sjoerg 148238603Sjoerg if (xfr_intr == NULL) 149238603Sjoerg { 150269879Semaste fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv)); 151238603Sjoerg return; 152238603Sjoerg } 153238603Sjoerg 154238603Sjoerg /* 155238603Sjoerg * Open the interrupt transfer. 156238603Sjoerg */ 157238603Sjoerg if ((rv = libusb20_tr_open(xfr_intr, 0, 1, intr_ep)) != 0) 158238603Sjoerg { 159269879Semaste fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv)); 160238603Sjoerg return; 161238603Sjoerg } 162238603Sjoerg 163238603Sjoerg uint8_t in_buf[BUFLEN]; 164238603Sjoerg uint32_t rlen; 165238603Sjoerg 166238603Sjoerg if ((rv = libusb20_tr_bulk_intr_sync(xfr_intr, in_buf, BUFLEN, &rlen, TIMEOUT)) 167238603Sjoerg != 0) 168238603Sjoerg { 169269879Semaste fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv)); 170238603Sjoerg } 171238603Sjoerg printf("received %d bytes\n", rlen); 172238603Sjoerg if (rlen > 0) 173238603Sjoerg print_formatted(in_buf, rlen); 174238603Sjoerg 175238603Sjoerg libusb20_tr_close(xfr_intr); 176238603Sjoerg } 177238603Sjoerg 178238603Sjoerg libusb20_dev_close(dev); 179238603Sjoerg} 180238603Sjoerg 181238603Sjoergstatic void 182238603Sjoergusage(void) 183238603Sjoerg{ 184238603Sjoerg fprintf(stderr, 185238603Sjoerg "Usage ./usb [-i <INTR_EP>] -v <VID> -p <PID> [dir type rcpt req wValue wIndex wLength [<outdata> ...]]\n"); 186238603Sjoerg exit(EX_USAGE); 187238603Sjoerg} 188238603Sjoerg 189238603Sjoergstatic const char *reqnames[] = 190238603Sjoerg{ 191238603Sjoerg "get_status", 192238603Sjoerg "clear_feature", 193238603Sjoerg "res1", 194238603Sjoerg "set_feature", 195238603Sjoerg "res2", 196238603Sjoerg "set_address", 197238603Sjoerg "get_descriptor", 198238603Sjoerg "set_descriptor", 199238603Sjoerg "get_configuration", 200238603Sjoerg "set_configuration", 201238603Sjoerg "get_interface", 202238603Sjoerg "set_interface", 203238603Sjoerg "synch_frame", 204238603Sjoerg}; 205238603Sjoerg 206238603Sjoergstatic int 207238603Sjoergget_req(const char *reqname) 208238603Sjoerg{ 209238603Sjoerg size_t i; 210238603Sjoerg size_t l = strlen(reqname); 211238603Sjoerg 212238603Sjoerg for (i = 0; 213238603Sjoerg i < sizeof reqnames / sizeof reqnames[0]; 214238603Sjoerg i++) 215238603Sjoerg if (strncasecmp(reqname, reqnames[i], l) == 0) 216238603Sjoerg return i; 217238603Sjoerg 218238603Sjoerg return strtoul(reqname, 0, 0); 219238603Sjoerg} 220238603Sjoerg 221238603Sjoerg 222238603Sjoergstatic int 223238603Sjoergparse_req(int argc, char **argv) 224238603Sjoerg{ 225238603Sjoerg int idx; 226238603Sjoerg uint8_t rt = 0; 227238603Sjoerg 228238603Sjoerg for (idx = 0; argc != 0 && idx <= 6; argc--, idx++) 229238603Sjoerg switch (idx) 230238603Sjoerg { 231238603Sjoerg case 0: 232238603Sjoerg /* dir[ection]: i[n] | o[ut] */ 233238603Sjoerg if (*argv[idx] == 'i') 234238603Sjoerg rt |= 0x80; 235238603Sjoerg else if (*argv[idx] == 'o') 236238603Sjoerg /* nop */; 237238603Sjoerg else 238238603Sjoerg { 239238603Sjoerg fprintf(stderr, "request direction must be \"in\" or \"out\" (got %s)\n", 240238603Sjoerg argv[idx]); 241238603Sjoerg return -1; 242238603Sjoerg } 243238603Sjoerg break; 244238603Sjoerg 245238603Sjoerg case 1: 246238603Sjoerg /* type: s[tandard] | c[lass] | v[endor] */ 247238603Sjoerg if (*argv[idx] == 's') 248238603Sjoerg /* nop */; 249238603Sjoerg else if (*argv[idx] == 'c') 250238603Sjoerg rt |= 0x20; 251238603Sjoerg else if (*argv[idx] == 'v') 252238603Sjoerg rt |= 0x40; 253238603Sjoerg else 254238603Sjoerg { 255238603Sjoerg fprintf(stderr, 256238603Sjoerg "request type must be one of \"standard\", \"class\", or \"vendor\" (got %s)\n", 257238603Sjoerg argv[idx]); 258238603Sjoerg return -1; 259238603Sjoerg } 260238603Sjoerg break; 261238603Sjoerg 262238603Sjoerg case 2: 263238603Sjoerg /* rcpt: d[evice], i[nterface], e[ndpoint], o[ther] */ 264238603Sjoerg if (*argv[idx] == 'd') 265238603Sjoerg /* nop */; 266238603Sjoerg else if (*argv[idx] == 'i') 267238603Sjoerg rt |= 1; 268238603Sjoerg else if (*argv[idx] == 'e') 269238603Sjoerg rt |= 2; 270238603Sjoerg else if (*argv[idx] == 'o') 271238603Sjoerg rt |= 3; 272238603Sjoerg else 273238603Sjoerg { 274238603Sjoerg fprintf(stderr, 275238603Sjoerg "recipient must be one of \"device\", \"interface\", \"endpoint\", or \"other\" (got %s)\n", 276238603Sjoerg argv[idx]); 277238603Sjoerg return -1; 278238603Sjoerg } 279238603Sjoerg setup.bmRequestType = rt; 280238603Sjoerg break; 281238603Sjoerg 282238603Sjoerg case 3: 283238603Sjoerg setup.bRequest = get_req(argv[idx]); 284238603Sjoerg break; 285238603Sjoerg 286238603Sjoerg case 4: 287238603Sjoerg setup.wValue = strtoul(argv[idx], 0, 0); 288238603Sjoerg break; 289238603Sjoerg 290238603Sjoerg case 5: 291238603Sjoerg setup.wIndex = strtoul(argv[idx], 0, 0); 292238603Sjoerg break; 293238603Sjoerg 294238603Sjoerg case 6: 295238603Sjoerg setup.wLength = strtoul(argv[idx], 0, 0); 296238603Sjoerg break; 297238603Sjoerg } 298238603Sjoerg 299238603Sjoerg return argc; 300238603Sjoerg} 301238603Sjoerg 302238603Sjoerg 303238603Sjoergint 304238603Sjoergmain(int argc, char **argv) 305238603Sjoerg{ 306238603Sjoerg unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */ 307238603Sjoerg int c; 308238603Sjoerg 309238603Sjoerg /* 310238603Sjoerg * Initialize setup struct. This step is required, and initializes 311238603Sjoerg * internal fields in the struct. 312238603Sjoerg * 313238603Sjoerg * All the "public" fields are named exactly the way as the USB 314238603Sjoerg * standard describes them, namely: 315238603Sjoerg * 316238603Sjoerg * setup.bmRequestType: bitmask, bit 7 is direction 317238603Sjoerg * bits 6/5 is request type 318238603Sjoerg * (standard, class, vendor) 319238603Sjoerg * bits 4..0 is recipient 320238603Sjoerg * (device, interface, endpoint, 321238603Sjoerg * other) 322238603Sjoerg * setup.bRequest: the request itself (see get_req() for standard 323238603Sjoerg * requests, or specific value) 324238603Sjoerg * setup.wValue: a 16-bit value 325238603Sjoerg * setup.wIndex: another 16-bit value 326238603Sjoerg * setup.wLength: length of associated data transfer, direction 327238603Sjoerg * depends on bit 7 of bmRequestType 328238603Sjoerg */ 329238603Sjoerg LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup); 330238603Sjoerg 331238603Sjoerg while ((c = getopt(argc, argv, "i:p:v:")) != -1) 332238603Sjoerg switch (c) 333238603Sjoerg { 334238603Sjoerg case 'i': 335238603Sjoerg intr_ep = strtol(optarg, NULL, 0); 336238603Sjoerg break; 337238603Sjoerg 338238603Sjoerg case 'p': 339238603Sjoerg pid = strtol(optarg, NULL, 0); 340238603Sjoerg break; 341238603Sjoerg 342238603Sjoerg case 'v': 343238603Sjoerg vid = strtol(optarg, NULL, 0); 344238603Sjoerg break; 345238603Sjoerg 346238603Sjoerg default: 347238603Sjoerg usage(); 348238603Sjoerg break; 349238603Sjoerg } 350238603Sjoerg argc -= optind; 351238603Sjoerg argv += optind; 352238603Sjoerg 353238603Sjoerg if (vid != UINT_MAX || pid != UINT_MAX) 354238603Sjoerg { 355238603Sjoerg if (intr_ep != 0 && (intr_ep & 0x80) == 0) 356238603Sjoerg { 357238603Sjoerg fprintf(stderr, "Interrupt endpoint must be of type IN\n"); 358238603Sjoerg usage(); 359238603Sjoerg } 360238603Sjoerg 361238603Sjoerg if (argc > 0) 362238603Sjoerg { 363238603Sjoerg do_request = true; 364238603Sjoerg 365238603Sjoerg int rv = parse_req(argc, argv); 366238603Sjoerg if (rv < 0) 367238603Sjoerg return EX_USAGE; 368238603Sjoerg argc = rv; 369238603Sjoerg 370238603Sjoerg if (argc > 0) 371238603Sjoerg { 372238603Sjoerg for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--) 373238603Sjoerg { 374238603Sjoerg unsigned n = strtoul(argv[out_len], 0, 0); 375238603Sjoerg if (n > 255) 376238603Sjoerg fprintf(stderr, 377238603Sjoerg "Warning: data #%d 0x%0x > 0xff, truncating\n", 378238603Sjoerg out_len, n); 379238603Sjoerg out_buf[out_len] = (uint8_t)n; 380238603Sjoerg } 381238603Sjoerg out_len++; 382238603Sjoerg if (argc > 0) 383238603Sjoerg fprintf(stderr, 384238603Sjoerg "Data count exceeds maximum of %d, ignoring %d elements\n", 385238603Sjoerg BUFLEN, optind); 386238603Sjoerg } 387238603Sjoerg } 388238603Sjoerg } 389238603Sjoerg 390238603Sjoerg struct libusb20_backend *be; 391238603Sjoerg struct libusb20_device *dev; 392238603Sjoerg 393238603Sjoerg if ((be = libusb20_be_alloc_default()) == NULL) 394238603Sjoerg { 395238603Sjoerg perror("libusb20_be_alloc()"); 396238603Sjoerg return 1; 397238603Sjoerg } 398238603Sjoerg 399238603Sjoerg dev = NULL; 400238603Sjoerg while ((dev = libusb20_be_device_foreach(be, dev)) != NULL) 401238603Sjoerg { 402238603Sjoerg struct LIBUSB20_DEVICE_DESC_DECODED *ddp = 403238603Sjoerg libusb20_dev_get_device_desc(dev); 404238603Sjoerg 405238603Sjoerg printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n", 406238603Sjoerg libusb20_dev_get_desc(dev), 407238603Sjoerg ddp->idVendor, ddp->idProduct); 408238603Sjoerg 409238603Sjoerg if (ddp->idVendor == vid && ddp->idProduct == pid) 410238603Sjoerg doit(dev); 411238603Sjoerg } 412238603Sjoerg 413238603Sjoerg libusb20_be_free(be); 414238603Sjoerg return 0; 415238603Sjoerg} 416