[Nut-upsdev] Re: Tr : NUT patches
Peter Selinger
selinger at mathstat.dal.ca
Tue Aug 30 22:03:42 UTC 2005
Charles Lepple wrote:
>
> On 8/29/05, Peter Selinger <selinger at mathstat.dal.ca> wrote:
> > Charles, I finally got my hands on that hex dump. Here is descriptor
> > 22/0, from an APC Back-UPS ES 650:
>
> Thanks! (That passed through my rudimentary HID descriptor parser just
> fine, but then again, it's more of a tokenizer - it doesn't have all
> of the functionality of the MGE HIDParser code yet.)
>
> A couple of questions, if you don't mind...
>
> What tool did you use to extract that?
I did that with a little custom program called "get_descriptor.c". The
source is attached below.
> Also, what does the "descriptor 22/0" designation refer to?
As you probably know, a USB device communicates its capabilities via a
bunch of "descriptors". There are 5 standard descriptor types defined
in the USB specification, Section 9.6 [1]:
0x01 = device descriptor
0x02 = configuration descriptor
0x03 = string descriptor
0x04 = interface descriptor
0x05 = endpoint descriptor.
Further, the HID class specification defines some additional
descriptors in Section 6.2 [2]:
0x21 = HID descriptor
0x22 = report descriptor
0x23 = physical descriptor
There can be more than one descriptor of a given type, identified by
an "index" and possibly a "language ID" (see [1] Sec. 9.4.3).
The report descriptor of a HID device is always descriptor number
0x22, index 0. This is what I meant by "descriptor 22/0".
[1] the USB specification, http://www.usb.org/developers/docs/usb_20_02212005.zip
[2] the USB HID specification, http://www.usb.org/developers/devclass_docs/HID1_11.pdf
> Do you have the file 'hidparser-example.txt' that was in the original
> email you sent to Arnaud?
I believe I already sent that to you (and to the mailing list) on
August 26. The file is also contained in the tarball that Arnaud
posted to the bug tracker at:
https://alioth.debian.org/tracker/index.php?func=detail&aid=302101&group_id=30602&atid=411544
("Download" at the bottom of the page).
----------------------------------------------------------------------
/* get_descriptor.c: a simple tool to get a descriptor from a USB
device. Uses the libusb API, see http://libusb.sourceforge.net/doc/ */
/* NOTE: don't run this program on your USB mouse or keyboard: it will
detach the kernel driver and leave your computer pretty useless. */
/* Copyright (C) 2005 Peter Selinger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
/* Usage:
get_descriptor <bus> <device> <configuration> <interface> <altsetting> <endpoint> <descriptor> <index>
for example
get_descriptor 005 003 0 0 0 128 0x22 0
is what I used to get the device descriptor of my USB.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
/* the next invlude is not mentioned in the libusb documentation, but
evidently needed */
#include <usb.h>
/* ---------------------------------------------------------------------- */
/* general-purpose auxiliary functions */
/* write a hexdump of buf[0]..buf[len-1] to fout */
void hexdump(FILE *fout, char *buf, int len) {
int i;
for (i=0; i<len; i++) {
if ((i % 24) == 0) {
fprintf(fout, "\n");
}
fprintf(fout, " %02x", (unsigned char)buf[i]);
}
fprintf(fout, "\n");
}
/* write an ASCII dump of buf[0]..buf[len-1] to fout */
void asciidump(FILE *fout, char *buf, int len) {
int i;
for (i=0; i<len; i++) {
if ((i % 72) == 0) {
fprintf(fout, "\n ");
}
fprintf(fout, "%c", buf[i] >= 32 && buf[i] < 127 ? buf[i] : '.');
}
fprintf(fout, "\n");
}
/* convert string to integer. Return -1 on invalid string. */
int mystrtol(char *s) {
int r;
char *p;
r = strtol(s, &p, 0);
if (*s == 0 || *p != 0) {
return -1;
}
return r;
}
/* ---------------------------------------------------------------------- */
/* auxiliary USB functions */
/* claim interface, detaching any kernel driver if necessary */
int usb_claim_interface_with_detach(usb_dev_handle *dev, int interface) {
int r;
r = usb_claim_interface(dev, interface);
#if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
if (r == -EBUSY) {
r = usb_detach_kernel_driver_np(dev, interface);
if (r == 0) {
r = usb_claim_interface(dev, interface);
}
}
#endif
return r;
}
/* ---------------------------------------------------------------------- */
/* user interface */
void usage(FILE *fout, char *myname) {
fprintf(fout, "Usage: %s <bus> <device> <configuration> <interface> <altsetting> <endpoint> <descriptor> <index>\n", myname);
}
int main(int ac, char *av[]) {
struct usb_bus *bus;
struct usb_device *dev;
struct usb_config_descriptor *con;
struct usb_interface *inter;
struct usb_interface_descriptor *alt;
struct usb_endpoint_descriptor *end;
int i, r;
int err = 0;
char buf[2048];
usb_dev_handle *udev;
FILE *fout = stdout;
char *myname, *arg_bus, *arg_dev;
int arg_con, arg_int, arg_alt, arg_end, arg_typ, arg_ind;
/* required initializations */
usb_init();
usb_find_busses();
usb_find_devices();
myname = av[0];
av++;
ac--;
/* command line options */
if (ac != 8) {
fprintf(stderr, "Wrong number of arguments.\n");
usage(stderr, myname);
exit(1);
}
arg_bus = av[0];
arg_dev = av[1];
arg_con = mystrtol(av[2]);
arg_int = mystrtol(av[3]);
arg_alt = mystrtol(av[4]);
arg_end = mystrtol(av[5]);
arg_typ = mystrtol(av[6]);
arg_ind = mystrtol(av[7]);
/* find the requested bus */
for (bus = usb_get_busses(); bus; bus = bus->next) {
if (strcmp(bus->dirname, arg_bus) == 0) {
break;
}
}
if (!bus) {
fprintf(stderr, "There is no bus %s.\n", arg_bus);
fprintf(stderr, "Possible values:");
for (bus = usb_get_busses(); bus; bus = bus->next) {
fprintf(stderr, " %s", bus->dirname);
}
fprintf(stderr, "\n");
exit(2);
}
/* find the requested device */
for (dev = bus->devices; dev; dev = dev->next) {
if (strcmp(dev->filename, arg_dev) == 0) {
break;
}
}
if (!dev) {
fprintf(stderr, "Bus %s has no device %s.\n", arg_bus, arg_dev);
fprintf(stderr, "Possible values:");
for (dev = bus->devices; dev; dev = dev->next) {
fprintf(stderr, " %s", dev->filename);
}
fprintf(stderr, "\n");
exit(2);
}
/* find the requested configuration */
if (arg_con < 0 || arg_con >= dev->descriptor.bNumConfigurations) {
fprintf(stderr, "Bus %s device %s has no configuration %d.\n", arg_bus, arg_dev, arg_con);
fprintf(stderr, "Possible values: 0--%d\n", dev->descriptor.bNumConfigurations-1);
exit(2);
}
con = &dev->config[arg_con];
/* find the requested interface */
if (arg_int < 0 || arg_int >= con->bNumInterfaces) {
fprintf(stderr, "Bus %s device %s configuration %d has no interface %d.\n", arg_bus, arg_dev, arg_con, arg_int);
fprintf(stderr, "Possible values: 0--%d\n", con->bNumInterfaces-1);
exit(2);
}
inter = &con->interface[arg_int];
/* find the requested alternative setting */
if (arg_alt < 0 || arg_alt >= inter->num_altsetting) {
fprintf(stderr, "Bus %s device %s configuration %d interface %d has no altsetting %d.\n", arg_bus, arg_dev, arg_con, arg_int, arg_alt);
fprintf(stderr, "Possible values: 0--%d\n", inter->num_altsetting-1);
exit(2);
}
alt = &inter->altsetting[arg_alt];
/* find the requested endpoint */
if (arg_end != 128) {
for (i = 0; i < alt->bNumEndpoints; i++) {
end = &alt->endpoint[i];
if (end->bEndpointAddress == arg_end) {
break;
}
}
if (i >= alt->bNumEndpoints) {
fprintf(stderr, "Bus %s device %s configuration %d interface %d altsetting %d has no endpoint %d.\n", arg_bus, arg_dev, arg_con, arg_int, arg_alt, arg_end);
fprintf(stderr, "Possible values: 128");
for (i = 0; i < alt->bNumEndpoints; i++) {
end = &alt->endpoint[i];
fprintf(stderr, " %d", end->bEndpointAddress);
}
fprintf(stderr, "\n");
exit(2);
}
}
/* OK, we got all the information. Now try to fetch the descriptor */
/* open the device */
udev = usb_open(dev);
if (!udev) {
fprintf(fout, "Can't open bus %s device %s: %s\n", arg_bus, arg_dev, usb_strerror());
exit(3);
}
/* set the configuration */
r = usb_set_configuration(udev, con->bConfigurationValue);
if (r<0) {
fprintf(fout, "Warning: %s\n", usb_strerror());
err = 3;
}
/* claim the interface */
r = usb_claim_interface_with_detach(udev, alt->bInterfaceNumber);
if (r<0) {
fprintf(fout, "Warning: %s\n", usb_strerror());
err = 3;
}
/* set altsetting */
r = usb_set_altinterface(udev, alt->bAlternateSetting);
if (r<0) {
fprintf(fout, "Warning: %s\n", usb_strerror());
err = 3;
}
/* get the descriptor for this endpoint, type, index */
r = usb_get_descriptor_by_endpoint(udev, arg_end, arg_typ, arg_ind, buf, sizeof(buf));
if (r < 0) {
fprintf(fout, "Can't get endpoint %d descriptor 0x%02x index %d: %s\n", arg_end, arg_typ, arg_ind, usb_strerror());
err = 3;
goto done;
}
fprintf(stderr, "Bus %s device %s configuration %d interface %d altsetting %d endpoint %d descriptor 0x%02x index %d:\n", arg_bus, arg_dev, arg_con, arg_int, arg_alt, arg_end, arg_typ, arg_ind);
hexdump(fout, buf, r);
asciidump(fout, buf, r);
done:
usb_close(udev);
if (err && getuid() != 0) {
fprintf(fout, "Try running this program as root, or as the owner of /proc/bus/usb/%s/%s.\n", arg_bus, arg_dev);
}
return err;
}
More information about the Nut-upsdev
mailing list