aboutsummaryrefslogtreecommitdiffstats
path: root/examples/usbtool
diff options
context:
space:
mode:
authorChristian Starkjohann <cs+github@obdev.at>2008-04-17 19:00:20 +0000
committerChristian Starkjohann <cs+github@obdev.at>2008-04-17 19:00:20 +0000
commit95ca3f5bd696b5450820929e1b1a444d02f0bd1e (patch)
tree70ac0161a0e4548acaf2f89d2ecb77132579ff7a /examples/usbtool
parent2f465daef9e6c5a6b7bda3074c050cd7e8515770 (diff)
downloadv-usb-95ca3f5bd696b5450820929e1b1a444d02f0bd1e.tar.gz
v-usb-95ca3f5bd696b5450820929e1b1a444d02f0bd1e.tar.bz2
v-usb-95ca3f5bd696b5450820929e1b1a444d02f0bd1e.zip
- imported new files into project
Diffstat (limited to 'examples/usbtool')
-rw-r--r--examples/usbtool/Makefile48
-rw-r--r--examples/usbtool/Makefile.windows18
-rw-r--r--examples/usbtool/Readme.txt209
-rwxr-xr-xexamples/usbtool/make-files.sh16
-rw-r--r--examples/usbtool/usbtool.c356
5 files changed, 647 insertions, 0 deletions
diff --git a/examples/usbtool/Makefile b/examples/usbtool/Makefile
new file mode 100644
index 0000000..f79fc03
--- /dev/null
+++ b/examples/usbtool/Makefile
@@ -0,0 +1,48 @@
+# Name: Makefile
+# Project: usbtool
+# Author: Christian Starkjohann
+# Creation Date: 2008-04-06
+# Tabsize: 4
+# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
+# This Revision: $Id$
+
+
+# Concigure the following definitions according to your system.
+# This Makefile has been tested on Mac OS X, Linux and Windows.
+
+# Use the following 3 lines on Unix (uncomment the framework on Mac OS X):
+USBFLAGS = `libusb-config --cflags`
+USBLIBS = `libusb-config --libs`
+EXE_SUFFIX =
+
+# Use the following 3 lines on Windows and comment out the 3 above. You may
+# have to change the include paths to where you installed libusb-win32
+#USBFLAGS = -I/usr/local/include
+#USBLIBS = -L/usr/local/lib -lusb
+#EXE_SUFFIX = .exe
+
+NAME = usbtool
+
+OBJECTS = opendevice.o $(NAME).o
+
+CC = gcc
+CFLAGS = $(USBFLAGS) -O -g -Wall
+LIBS = $(USBLIBS)
+
+PROGRAM = $(NAME)$(EXE_SUFFIX)
+
+
+all: $(PROGRAM)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+$(PROGRAM): $(OBJECTS)
+ $(CC) -o $(PROGRAM) $(OBJECTS) $(LIBS)
+
+strip: $(PROGRAM)
+ strip $(PROGRAM)
+
+clean:
+ rm -f *.o $(PROGRAM)
diff --git a/examples/usbtool/Makefile.windows b/examples/usbtool/Makefile.windows
new file mode 100644
index 0000000..1c4aaa1
--- /dev/null
+++ b/examples/usbtool/Makefile.windows
@@ -0,0 +1,18 @@
+# Name: Makefile.windows
+# Project: usbtool
+# Author: Christian Starkjohann
+# Creation Date: 2008-04-06
+# Tabsize: 4
+# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
+# This Revision: $Id$
+
+# You may use this file with
+# make -f Makefile.windows
+# on Windows with MinGW instead of editing the main Makefile.
+
+include Makefile
+
+USBFLAGS = -I/usr/local/mingw/include
+USBLIBS = -L/usr/local/mingw/lib -lusb
+EXE_SUFFIX = .exe
diff --git a/examples/usbtool/Readme.txt b/examples/usbtool/Readme.txt
new file mode 100644
index 0000000..33f527c
--- /dev/null
+++ b/examples/usbtool/Readme.txt
@@ -0,0 +1,209 @@
+This is the Readme file for usbtool, a general purpose command line utility
+which can send USB requests to arbitrary devices. Usbtool is based on libusb.
+
+
+WHAT IS USBTOOL GOOD FOR?
+=========================
+When you implement a communication protocol like USB, you must usually write
+two programs: one on each end of the communication. For USB, this means that
+you must write a firmware for the device and driver software for the host.
+
+Usbtool can save you the work of writing the host software, at least during
+firmware development and testing. Usbtool can send control-in and -out
+requests to arbitrary devices and send and receive data on interrupt- and
+bulk-endpoints.
+
+Usbtool is not only a useful developer tool, it's also an example for using
+libusb for communication with the device.
+
+
+SYNOPSIS
+========
+ usbtool [options] <command>
+
+
+COMMANDS
+========
+ list
+ This command prints a list of devices found on all available USB busses.
+ Options -v, -V, -p and -P can be used to filter the list.
+
+ control in|out <type> <recipient> <request> <value> <index>
+ Sends a control-in or control-out request to the device. The request
+ parameters are:
+ type ........ Type of request, can be "standard", "class", "vendor" or
+ "reserved". The type determines which software module in
+ the device is responsible for answering the request:
+ Standard requests are answered by the driver, class
+ requests by the class implementation (e.g. HID, CDC) and
+ vendor requests by custom code.
+ recipient ... Recipient of the request in the device. Can be "device",
+ "interface", "endpoint" or "other". For standard and
+ class requests, the specification defines a recipient for
+ each request. For vendor requests, choose whatever your
+ code expects.
+ request ..... 8 bit numeric value identifying the request.
+ value ....... 16 bit numeric value passed to the device.
+ index ....... another 16 bit numeric value passed to the device.
+ Use options -v, -V, -p and -P to single out a particular device. Use
+ options -d or -D to to send data in an OUT request. Use options -n, -O
+ and -b to determine what to do with data received in an IN request.
+
+ interrupt in|out
+ Sends or receives data on an interrupt-out resp. -in endpoint.
+ Use options -v, -V, -p and -P to single out a particular device. Use
+ options -d or -D to to send data to an OUT endpoint. Use options -n, -O
+ and -b to determine what to do with data received from an IN endpoint.
+ Use option -e to set the endpoint number, -c to choose a configuration
+ -i to claim a particular interface.
+
+ bulk in|out
+ Same as "interrupt in" and "interrupt out", but for bulk endpoints.
+
+
+OPTIONS
+=======
+Most options have already been mentioned at the commands which use them.
+here is a complete list:
+
+ -h or -?
+ Prints a short help.
+
+ -v <vendor-id>
+ Numeric vendor ID, can be "*" to allow any VID. Take only devices with
+ matching vendor ID into account.
+
+ -p <product-id>
+ Numeric product ID, can be "*" to allow any PID. Take only devices with
+ matching product ID into account.
+
+ -V <vendor-name-pattern>
+ Shell style matching pattern for vendor name. Take only devices into
+ account which have a vendor name that matches this pattern.
+
+ -P <product-name-pattern>
+ Shell style matching pattern for product name. Take only devices into
+ account which have a product name that matches this pattern.
+
+ -S <serial-pattern>
+ Shell style matching pattern for serial number. Take only devices into
+ account which have a serial number that matches this pattern.
+
+ -d <databytes>
+ Data bytes to send to the device, comma separated list of numeric values.
+ E.g.: "1,2,3,4,5".
+
+ -D <file>
+ Binary data sent to the device should be taken from this file.
+
+ -O <file>
+ Write received data bytes to the given file. Format is either hex or
+ binary, depending on the -b flag. By default, received data is printed
+ to standard output.
+
+ -b
+ Request binary output format for files and standard output. Default is
+ a hexadecimal listing.
+
+ -n <count>
+ Numeric value: Maximum number of bytes to receive. This value is passed
+ directly to the libusb API functions.
+
+ -e <endpoint>
+ Numeric value: Endpoint number for interrupt and bulk commands.
+
+ -t <timeout>
+ Numeric value: Timeout in milliseconds for the request. This value is
+ passed directly to the libusb API functions.
+
+ -c <configuration>
+ Numeric value: Interrupt and bulk endpoints can usually only be used if
+ a configuration and an interface has been chosen. Use -c and -i to
+ specify configuration and interface values.
+
+ -i <interface>
+ Numeric value: Interrupt and bulk endpoints can usually only be used if
+ a configuration and an interface has been chosen. Use -c and -i to
+ specify configuration and interface values.
+
+ -w
+ Usbtool may be too verbose with warnings for some applications. Use this
+ option to suppress USB warnings.
+
+
+NUMERIC VALUES
+==============
+All numeric values can be given in hexadecimal, decimal or octal. Hex values
+are identified by their 0x or 0X prefix, octal values by a leading "0" (the
+digit zero) and decimal values because they start with a non-zero digit. An
+optional sign character is allowed. The special value "*" is translated to
+zero and stands for "any value" in some contexts.
+
+
+SHELL STYLE MATCHING PATTERNS
+=============================
+Some options take shell style matching patterns as an argument. This refers
+to Unix shells and their file wildcard operations:
+ + "*" (asterisk character) matches any number (0 to infinite) of any
+ characters.
+ + "?" matches exactly one arbitrary character.
+ + A list of characters in square brackets (e.g. "[abc]") matches any of the
+ characters in the list. If a dash ("-") is in the list, it must be the
+ first or the last character. If a caret ("^") is in the list, it must
+ not be the first character. A closing square bracket ("]") must be the
+ first character in the list. A range of characters can be specified in
+ the way "[a-z]". This matches all characters with numeric representation
+ (usually ASCII) starting with "a" and ending with "z". The entire
+ construct matches only one character.
+ + A list of characters in square brackets starting with a caret ("^"), e.g.
+ ("[^abc]") matches any character NOT in the list. The other rules are as
+ above.
+ + "\" (backslash) followed by any character matches that following
+ character. This can be used to escape "*", "?", "[" and "\".
+
+
+BUILDING USBTOOL
+================
+Usbtool uses libusb on Unix and libusb-win32 on Windows. These libraries can
+be obtained from http://libusb.sourceforge.net/ and
+http://libusb-win32.sourceforge.net/ respectively. On Unix, a simple "make"
+should compile the sources (although you may have to edit Makefile to
+include or remove additional libraries). On Windows, we recommend that you
+use MinGW and MSYS. See the top level Readme file for details. Edit
+Makefile.windows according to your library installation paths and build with
+"make -f Makefile.windows".
+
+
+EXAMPLES
+========
+To list all devices connected to your computer, do
+
+ usbtool -w list
+
+To check whether our selection options single out the desired device, use eg.
+
+ usbtool -w -P LEDControl list
+
+This command shows all LEDControl devices connected or prints nothing if
+none is found. LEDControl is the device from the "custom-class" example.
+
+You can also send commands to the LEDControl device using usbtool. From
+the file requests.h in custom-class/firmware, we know that the set-status
+request has numeric value 1 and the get-status request is 2. See this file
+for details of the protocol used. We can therefore query the status with
+
+ usbtool -w -P LEDControl control in vendor device 2 0 0
+
+This command prints 0x00 if the LED is off or 0x01 if it is on. To turn the
+LED on, use
+
+ usbtool -w -P LEDControl control out vendor device 1 1 0
+
+and to turn it off, use
+
+ usbtool -w -P LEDControl control out vendor device 1 0 0
+
+
+----------------------------------------------------------------------------
+(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH.
+http://www.obdev.at/
diff --git a/examples/usbtool/make-files.sh b/examples/usbtool/make-files.sh
new file mode 100755
index 0000000..0ba183e
--- /dev/null
+++ b/examples/usbtool/make-files.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Author: Christian Starkjohann
+# Creation Date: 2008-04-17
+# Tabsize: 4
+# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
+# This Revision: $Id$
+
+
+if [ "$1" = remove ]; then
+ make clean
+ rm -f opendevice.[ch]
+ exit
+fi
+
+cp ../../libs-host/opendevice.[ch] .
diff --git a/examples/usbtool/usbtool.c b/examples/usbtool/usbtool.c
new file mode 100644
index 0000000..fe29a06
--- /dev/null
+++ b/examples/usbtool/usbtool.c
@@ -0,0 +1,356 @@
+/* Name: usbtool.c
+ * Project: AVR-USB examples, host side
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-06
+ * Tabsize: 4
+ * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
+ * This Revision: $Id$
+ */
+
+/*
+General Description:
+This command line tool can perform various USB requests at arbitrary
+USB devices. It is intended as universal host side tool for experimentation
+and debugging purposes. It must be linked with libusb, a library for accessing
+the USB bus from Linux, FreeBSD, Mac OS X and other Unix operating systems.
+Libusb can be obtained from http://libusb.sourceforge.net/.
+On Windows use libusb-win32 from http://libusb-win32.sourceforge.net/.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <usb.h> /* this is libusb, see http://libusb.sourceforge.net/ */
+#include "opendevice.h" /* common code moved to separate module */
+
+#define DEFAULT_USB_VID 0 /* any */
+#define DEFAULT_USB_PID 0 /* any */
+
+static void usage(char *name)
+{
+ fprintf(stderr, "usage: %s [options] <command>\n", name);
+ fprintf(stderr,
+ "Options are:\n"
+ " -h or -? (print this help and exit)\n"
+ " -v <vendor-id> (defaults to 0x%x, can be '*' for any VID)\n"
+ " -p <product-id> (defaults to 0x%x, can be '*' for any PID)\n"
+ " -V <vendor-name-pattern> (shell style matching, defaults to '*')\n"
+ " -P <product-name-pattern> (shell style matching, defaults to '*')\n"
+ " -S <serial-pattern> (shell style matching, defaults to '*')\n"
+ " -d <databytes> (data byte for request, comma separated list)\n"
+ " -D <file> (binary data for request taken from file)\n"
+ " -O <file> (write received data bytes to file)\n"
+ " -b (binary output format, default is hex)\n"
+ " -n <count> (maximum number of bytes to receive)\n"
+ " -e <endpoint> (specify endpoint for some commands)\n"
+ " -t <timeout> (specify USB timeout in milliseconds)\n"
+ " -c <configuration> (device configuration to choose)\n"
+ " -i <interface> (configuration interface to claim)\n"
+ " -w (suppress USB warnings, default is verbose)\n"
+ "\n"
+ "Commands are:\n"
+ " list (list all matching devices by name)\n"
+ " control in|out <type> <recipient> <request> <value> <index> (send control request)\n"
+ " interrupt in|out (send or receive interrupt data)\n"
+ " bulk in|out (send or receive bulk data)\n"
+ "For valid enum values for <type> and <recipient> pass \"x\" for the value.\n"
+ "Objective Development's free VID/PID pairs are:\n"
+ " 5824/1500 for vendor class devices\n"
+ " 5824/1503 for HID class devices excluding mice and keyboards\n"
+ " 5824/1505 for CDC-ACM class devices\n"
+ " 5824/1508 for MIDI class devices\n"
+ , DEFAULT_USB_VID, DEFAULT_USB_PID
+ );
+
+
+}
+
+static int vendorID = DEFAULT_USB_VID;
+static int productID = DEFAULT_USB_PID;
+static char *vendorNamePattern = "*";
+static char *productNamePattern = "*";
+static char *serialPattern = "*";
+static char *sendBytes = NULL;
+static int sendByteCount;
+static char *outputFile = NULL;
+static int endpoint = 0;
+static int outputFormatIsBinary = 0;
+static int showWarnings = 1;
+static int usbTimeout = 5000;
+static int usbCount = 128;
+static int usbConfiguration = 1;
+static int usbInterface = 0;
+
+static int usbDirection, usbType, usbRecipient, usbRequest, usbValue, usbIndex; /* arguments of control transfer */
+
+/* ------------------------------------------------------------------------- */
+
+/* ASCII to integer (number parsing) which allows hex (0x prefix),
+ * octal (0 prefix) and decimal (1-9 prefix) input.
+ */
+static int myAtoi(char *text)
+{
+long l;
+char *endPtr;
+
+ if(strcmp(text, "*") == 0)
+ return 0;
+ l = strtol(text, &endPtr, 0);
+ if(endPtr == text){
+ fprintf(stderr, "warning: can't parse numeric parameter ->%s<-, defaults to 0.\n", text);
+ l = 0;
+ }else if(*endPtr != 0){
+ fprintf(stderr, "warning: numeric parameter ->%s<- only partially parsed.\n", text);
+ }
+ return l;
+}
+
+static int parseEnum(char *text, ...)
+{
+va_list vlist;
+char *entries[64];
+int i, numEntries;
+
+ va_start(vlist, text);
+ for(i = 0; i < 64; i++){
+ entries[i] = va_arg(vlist, char *);
+ if(entries[i] == NULL)
+ break;
+ }
+ numEntries = i;
+ va_end(vlist);
+ for(i = 0; i < numEntries; i++){
+ if(strcasecmp(text, entries[i]) == 0)
+ return i;
+ }
+ if(isdigit(*text)){
+ return myAtoi(text);
+ }
+ fprintf(stderr, "Enum value \"%s\" not allowed. Allowed values are:\n", text);
+ for(i = 0; i < numEntries; i++){
+ fprintf(stderr, " %s\n", entries[i]);
+ }
+ exit(1);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#define ACTION_LIST 0
+#define ACTION_CONTROL 1
+#define ACTION_INTERRUPT 2
+#define ACTION_BULK 3
+
+int main(int argc, char **argv)
+{
+usb_dev_handle *handle = NULL;
+int opt, len, action, argcnt;
+char *myName = argv[0], *s, *rxBuffer = NULL;
+FILE *fp;
+
+ while((opt = getopt(argc, argv, "?hv:p:V:P:S:d:D:O:e:n:tbw")) != -1){
+ switch(opt){
+ case 'h':
+ case '?': /* -h or -? (print this help and exit) */
+ usage(myName);
+ exit(1);
+ case 'v': /* -v <vendor-id> (defaults to 0x%x, can be '*' for any VID) */
+ vendorID = myAtoi(optarg);
+ break;
+ case 'p': /* -p <product-id> (defaults to 0x%x, can be '*' for any PID) */
+ productID = myAtoi(optarg);
+ break;
+ case 'V': /* -V <vendor-name-pattern> (shell style matching, defaults to '*') */
+ vendorNamePattern = optarg;
+ break;
+ case 'P': /* -P <product-name-pattern> (shell style matching, defaults to '*') */
+ productNamePattern = optarg;
+ break;
+ case 'S': /* -S <serial-pattern> (shell style matching, defaults to '*') */
+ serialPattern = optarg;
+ break;
+ case 'd': /* -d <databytes> (data bytes for requests given on command line) */
+ while((s = strtok(optarg, ", ")) != NULL){
+ optarg = NULL;
+ if(sendBytes != NULL){
+ sendBytes = realloc(sendBytes, sendByteCount + 1);
+ }else{
+ sendBytes = malloc(sendByteCount + 1);
+ }
+ sendBytes[sendByteCount++] = myAtoi(s);
+ }
+ break;
+ case 'D': /* -D <file> (data bytes for request taken from file) */
+ if((fp = fopen(optarg, "rb")) == NULL){
+ fprintf(stderr, "error opening %s: %s\n", optarg, strerror(errno));
+ exit(1);
+ }
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if(sendBytes != NULL){
+ sendBytes = realloc(sendBytes, sendByteCount + len);
+ }else{
+ sendBytes = malloc(sendByteCount + len);
+ }
+ fread(sendBytes + sendByteCount, 1, len, fp); /* would need error checking */
+ sendByteCount += len;
+ fclose(fp);
+ break;
+ case 'O': /* -O <file> (write received data bytes to file) */
+ outputFile = optarg;
+ break;
+ case 'e': /* -e <endpoint> (specify endpoint for some commands) */
+ endpoint = myAtoi(optarg);
+ break;
+ case 't': /* -t <timeout> (specify USB timeout in milliseconds) */
+ usbTimeout = myAtoi(optarg);
+ break;
+ case 'b': /* -b (binary output format, default is hex) */
+ outputFormatIsBinary = 1;
+ break;
+ case 'n': /* -n <count> (maximum number of bytes to receive) */
+ usbCount = myAtoi(optarg);
+ break;
+ case 'c': /* -c <configuration> (device configuration to choose) */
+ usbConfiguration = myAtoi(optarg);
+ break;
+ case 'i': /* -i <interface> (configuration interface to claim) */
+ usbInterface = myAtoi(optarg);
+ break;
+ case 'w': /* -w (suppress USB warnings, default is verbose) */
+ showWarnings = 0;
+ break;
+ default:
+ fprintf(stderr, "Option -%c unknown\n", opt);
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if(argc < 1){
+ usage(myName);
+ exit(1);
+ }
+ argcnt = 2;
+ if(strcasecmp(argv[0], "list") == 0){
+ action = ACTION_LIST;
+ argcnt = 1;
+ }else if(strcasecmp(argv[0], "control") == 0){
+ action = ACTION_CONTROL;
+ argcnt = 7;
+ }else if(strcasecmp(argv[0], "interrupt") == 0){
+ action = ACTION_INTERRUPT;
+ }else if(strcasecmp(argv[0], "bulk") == 0){
+ action = ACTION_BULK;
+ }else{
+ fprintf(stderr, "command %s not known\n", argv[0]);
+ usage(myName);
+ exit(1);
+ }
+ if(argc < argcnt){
+ fprintf(stderr, "Not enough arguments.\n");
+ usage(myName);
+ exit(1);
+ }
+ if(argc > argcnt){
+ fprintf(stderr, "Warning: only %d arguments expected, rest ignored.\n", argcnt);
+ }
+ usb_init();
+ if(usbOpenDevice(&handle, vendorID, vendorNamePattern, productID, productNamePattern, serialPattern, action == ACTION_LIST ? stdout : NULL, showWarnings ? stderr : NULL) != 0){
+ fprintf(stderr, "Could not find USB device with VID=0x%x PID=0x%x Vname=%s Pname=%s Serial=%s\n", vendorID, productID, vendorNamePattern, productNamePattern, serialPattern);
+ exit(1);
+ }
+ if(action == ACTION_LIST)
+ exit(0); /* we've done what we were asked to do already */
+ usbDirection = parseEnum(argv[1], "out", "in", NULL);
+ if(usbDirection){ /* IN transfer */
+ rxBuffer = malloc(usbCount);
+ }
+ if(action == ACTION_CONTROL){
+ int requestType;
+ usbType = parseEnum(argv[2], "standard", "class", "vendor", "reserved", NULL);
+ usbRecipient = parseEnum(argv[3], "device", "interface", "endpoint", "other", NULL);
+ usbRequest = myAtoi(argv[4]);
+ usbValue = myAtoi(argv[5]);
+ usbIndex = myAtoi(argv[6]);
+ requestType = ((usbDirection & 1) << 7) | ((usbType & 3) << 5) | (usbRecipient & 0x1f);
+ if(usbDirection){ /* IN transfer */
+ len = usb_control_msg(handle, requestType, usbRequest, usbValue, usbIndex, rxBuffer, usbCount, usbTimeout);
+ }else{ /* OUT transfer */
+ len = usb_control_msg(handle, requestType, usbRequest, usbValue, usbIndex, sendBytes, sendByteCount, usbTimeout);
+ }
+ }else{ /* must be ACTION_INTERRUPT or ACTION_BULK */
+ int retries = 1;
+ if(usb_set_configuration(handle, usbConfiguration) && showWarnings){
+ fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror());
+ }
+ /* now try to claim the interface and detach the kernel HID driver on
+ * linux and other operating systems which support the call.
+ */
+ while((len = usb_claim_interface(handle, usbInterface)) != 0 && retries-- > 0){
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+ if(usb_detach_kernel_driver_np(handle, 0) < 0 && showWarnings){
+ fprintf(stderr, "Warning: could not detach kernel driver: %s\n", usb_strerror());
+ }
+#endif
+ }
+ if(len != 0 && showWarnings)
+ fprintf(stderr, "Warning: could not claim interface: %s\n", usb_strerror());
+ if(action == ACTION_INTERRUPT){
+ if(usbDirection){ /* IN transfer */
+ len = usb_interrupt_read(handle, endpoint, rxBuffer, usbCount, usbTimeout);
+ }else{
+ len = usb_interrupt_write(handle, endpoint, sendBytes, sendByteCount, usbTimeout);
+ }
+ }else{
+ if(usbDirection){ /* IN transfer */
+ len = usb_bulk_read(handle, endpoint, rxBuffer, usbCount, usbTimeout);
+ }else{
+ len = usb_bulk_write(handle, endpoint, sendBytes, sendByteCount, usbTimeout);
+ }
+ }
+ }
+ if(len < 0){
+ fprintf(stderr, "USB error: %s\n", usb_strerror());
+ exit(1);
+ }
+ if(usbDirection == 0) /* OUT */
+ printf("%d bytes sent.\n", len);
+ if(rxBuffer != NULL){
+ FILE *fp = stdout;
+ if(outputFile != NULL){
+ fp = fopen(outputFile, outputFormatIsBinary ? "wb" : "w");
+ if(fp == NULL){
+ fprintf(stderr, "Error writing \"%s\": %s\n", outputFile, strerror(errno));
+ exit(1);
+ }
+ }
+ if(outputFormatIsBinary){
+ fwrite(rxBuffer, 1, len, fp);
+ }else{
+ int i;
+ for(i = 0; i < len; i++){
+ if(i != 0){
+ if(i % 16 == 0){
+ fprintf(fp, "\n");
+ }else{
+ fprintf(fp, " ");
+ }
+ }
+ fprintf(fp, "0x%02x", rxBuffer[i] & 0xff);
+ }
+ if(i != 0)
+ fprintf(fp, "\n");
+ }
+ }
+ usb_close(handle);
+ if(rxBuffer != NULL)
+ free(rxBuffer);
+ return 0;
+}