o cleanup

This commit is contained in:
optixx
2009-04-22 20:04:28 +02:00
parent 55e3468f74
commit 0c378a9f7c
1078 changed files with 0 additions and 0 deletions

View File

@@ -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), GNU GPL v3 or proprietary (CommercialLicense.txt)
# This Revision: $Id: Makefile 692 2008-11-07 15:07:40Z cs $
# 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 = $(CPPFLAGS) $(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)

View File

@@ -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), GNU GPL v3 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

View File

@@ -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/

View File

@@ -0,0 +1,203 @@
/* Name: opendevice.c
* Project: AVR-USB host-side library
* Author: Christian Starkjohann
* Creation Date: 2008-04-10
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: opendevice.c 692 2008-11-07 15:07:40Z cs $
*/
/*
General Description:
The functions in this module can be used to find and open a device based on
libusb or libusb-win32.
*/
#include <stdio.h>
#include "opendevice.h"
/* ------------------------------------------------------------------------- */
#define MATCH_SUCCESS 1
#define MATCH_FAILED 0
#define MATCH_ABORT -1
/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */
static int _shellStyleMatch(char *text, char *p)
{
int last, matched, reverse;
for(; *p; text++, p++){
if(*text == 0 && *p != '*')
return MATCH_ABORT;
switch(*p){
case '\\':
/* Literal match with following character. */
p++;
/* FALLTHROUGH */
default:
if(*text != *p)
return MATCH_FAILED;
continue;
case '?':
/* Match anything. */
continue;
case '*':
while(*++p == '*')
/* Consecutive stars act just like one. */
continue;
if(*p == 0)
/* Trailing star matches everything. */
return MATCH_SUCCESS;
while(*text)
if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED)
return matched;
return MATCH_ABORT;
case '[':
reverse = p[1] == '^';
if(reverse) /* Inverted character class. */
p++;
matched = MATCH_FAILED;
if(p[1] == ']' || p[1] == '-')
if(*++p == *text)
matched = MATCH_SUCCESS;
for(last = *p; *++p && *p != ']'; last = *p)
if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
matched = MATCH_SUCCESS;
if(matched == reverse)
return MATCH_FAILED;
continue;
}
}
return *text == 0;
}
/* public interface for shell style matching: returns 0 if fails, 1 if matches */
static int shellStyleMatch(char *text, char *pattern)
{
if(pattern == NULL) /* NULL pattern is synonymous to "*" */
return 1;
return _shellStyleMatch(text, pattern) == MATCH_SUCCESS;
}
/* ------------------------------------------------------------------------- */
int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen)
{
char buffer[256];
int rval, i;
if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
return rval;
if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0)
return rval;
if(buffer[1] != USB_DT_STRING){
*buf = 0;
return 0;
}
if((unsigned char)buffer[0] < rval)
rval = (unsigned char)buffer[0];
rval /= 2;
/* lossy conversion to ISO Latin1: */
for(i=1;i<rval;i++){
if(i > buflen) /* destination buffer overflow */
break;
buf[i-1] = buffer[2 * i];
if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
buf[i-1] = '?';
}
buf[i-1] = 0;
return i-1;
}
/* ------------------------------------------------------------------------- */
int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp)
{
struct usb_bus *bus;
struct usb_device *dev;
usb_dev_handle *handle = NULL;
int errorCode = USBOPEN_ERR_NOTFOUND;
usb_find_busses();
usb_find_devices();
for(bus = usb_get_busses(); bus; bus = bus->next){
for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */
if((vendorID == 0 || dev->descriptor.idVendor == vendorID)
&& (productID == 0 || dev->descriptor.idProduct == productID)){
char vendor[256], product[256], serial[256];
int len;
handle = usb_open(dev); /* we need to open the device in order to query strings */
if(!handle){
errorCode = USBOPEN_ERR_ACCESS;
if(warningsFp != NULL)
fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
continue;
}
/* now check whether the names match: */
len = vendor[0] = 0;
if(dev->descriptor.iManufacturer > 0){
len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor));
}
if(len < 0){
errorCode = USBOPEN_ERR_ACCESS;
if(warningsFp != NULL)
fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
}else{
errorCode = USBOPEN_ERR_NOTFOUND;
/* printf("seen device from vendor ->%s<-\n", vendor); */
if(shellStyleMatch(vendor, vendorNamePattern)){
len = product[0] = 0;
if(dev->descriptor.iProduct > 0){
len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product));
}
if(len < 0){
errorCode = USBOPEN_ERR_ACCESS;
if(warningsFp != NULL)
fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
}else{
errorCode = USBOPEN_ERR_NOTFOUND;
/* printf("seen product ->%s<-\n", product); */
if(shellStyleMatch(product, productNamePattern)){
len = serial[0] = 0;
if(dev->descriptor.iSerialNumber > 0){
len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial));
}
if(len < 0){
errorCode = USBOPEN_ERR_ACCESS;
if(warningsFp != NULL)
fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
}
if(shellStyleMatch(serial, serialNamePattern)){
if(printMatchingDevicesFp != NULL){
if(serial[0] == 0){
fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product);
}else{
fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial);
}
}else{
break;
}
}
}
}
}
}
usb_close(handle);
handle = NULL;
}
}
if(handle) /* we have found a deice */
break;
}
if(handle != NULL){
errorCode = 0;
*device = handle;
}
if(printMatchingDevicesFp != NULL) /* never return an error for listing only */
errorCode = 0;
return errorCode;
}
/* ------------------------------------------------------------------------- */

View File

@@ -0,0 +1,77 @@
/* Name: opendevice.h
* Project: AVR-USB host-side library
* Author: Christian Starkjohann
* Creation Date: 2008-04-10
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: opendevice.h 692 2008-11-07 15:07:40Z cs $
*/
/*
General Description:
This module offers additional functionality for host side drivers based on
libusb or libusb-win32. It includes a function to find and open a device
based on numeric IDs and textual description. It also includes a function to
obtain textual descriptions from a device.
To use this functionality, simply copy opendevice.c and opendevice.h into your
project and add them to your Makefile. You may modify and redistribute these
files according to the GNU General Public License (GPL) version 2 or 3.
*/
#ifndef __OPENDEVICE_H_INCLUDED__
#define __OPENDEVICE_H_INCLUDED__
#include <usb.h> /* this is libusb, see http://libusb.sourceforge.net/ */
#include <stdio.h>
int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen);
/* This function gets a string descriptor from the device. 'index' is the
* string descriptor index. The string is returned in ISO Latin 1 encoding in
* 'buf' and it is terminated with a 0-character. The buffer size must be
* passed in 'buflen' to prevent buffer overflows. A libusb device handle
* must be given in 'dev'.
* Returns: The length of the string (excluding the terminating 0) or
* a negative number in case of an error. If there was an error, use
* usb_strerror() to obtain the error message.
*/
int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp);
/* This function iterates over all devices on all USB busses and searches for
* a device. Matching is done first by means of Vendor- and Product-ID (passed
* in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard).
* When a device matches by its IDs, matching by names is performed. Name
* matching can be done on textual vendor name ('vendorNamePattern'), product
* name ('productNamePattern') and serial number ('serialNamePattern'). A
* device matches only if all non-null pattern match. If you don't care about
* a string, pass NULL for the pattern. Patterns are Unix shell style pattern:
* '*' stands for 0 or more characters, '?' for one single character, a list
* of characters in square brackets for a single character from the list
* (dashes are allowed to specify a range) and if the lis of characters begins
* with a caret ('^'), it matches one character which is NOT in the list.
* Other parameters to the function: If 'warningsFp' is not NULL, warning
* messages are printed to this file descriptor with fprintf(). If
* 'printMatchingDevicesFp' is not NULL, no device is opened but matching
* devices are printed to the given file descriptor with fprintf().
* If a device is opened, the resulting USB handle is stored in '*device'. A
* pointer to a "usb_dev_handle *" type variable must be passed here.
* Returns: 0 on success, an error code (see defines below) on failure.
*/
/* usbOpenDevice() error codes: */
#define USBOPEN_SUCCESS 0 /* no error */
#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */
#define USBOPEN_ERR_IO 2 /* I/O error */
#define USBOPEN_ERR_NOTFOUND 3 /* device not found */
/* Obdev's free USB IDs, see USBID-License.txt for details */
#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */
#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */
#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */
#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */
#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */
#endif /* __OPENDEVICE_H_INCLUDED__ */

View File

@@ -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), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbtool.c 692 2008-11-07 15:07:40Z cs $
*/
/*
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;
}