[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