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