[Nut-upsdev] TrippLite OMNI1000LCD hiddev

Peter Selinger selinger at mathstat.dal.ca
Wed Nov 9 02:05:02 UTC 2005


Joel Peshkin wrote:
> 
> Peter Selinger wrote:
> 
> >
> >
> >There is something fishy going on here. Perhaps related to parts of
> >the code being unaware of the true length of the report descriptor?
> >But I am really not sure. There should be a lot more variables,
> >because they are initially reported during the DumpTree. But later,
> >they are not found. Do you want to experiment a bit more with setting
> >the report descriptor length? You might even temporarily try to set it
> >to a constant value, since the actual length (618) is known for your
> >device. -- Peter
> >
> 
> I tried this hack and it didn't help.   I haven't delved deep enouh into 
> the code to know the right experiment to try next.  Any suggestions?

What I had in mind was to set

desc->wDescriptorLength = 618

not just to "return 618". 

> Also, I wonder if the fact that lsusb says.... "UNAVAILABLE" is an issue...
> 
>      iInterface              0
>         HID Device Descriptor:
>           bLength                 9
>           bDescriptorType        33
>           bcdHID               1.10
>           bCountryCode            0 Not supported
>           bNumDescriptors         1
>           bDescriptorType        34 Report
>           wDescriptorLength     618
>          Report Descriptors:
>            ** UNAVAILABLE **
>       Endpoint Descriptor:

Yes, but NUT has already read the Report Descriptor and dumped its
content quite correctly. What worries me more is that according to
lsusb, the Device Desciptor says the report descriptor is 618 bytes
long, but according to NUT, it says it is 459.

I would quite like to see the raw, unprocessed descriptors from your
device.

Attached is a little program (a slightly improved version of one that
I posted to the list in August, see
http://lists.alioth.debian.org/pipermail/nut-upsdev/2005-August/000088.html). 
This program reads raw descriptors from a USB device and prints them out.

I would be interested in the output (if any) of:

get_descriptor 001 003 1 0 0 128 0x01 0
get_descriptor 001 003 1 0 0 128 0x02 0
get_descriptor 001 003 1 0 0 128 0x03 0
get_descriptor 001 003 1 0 0 128 0x03 1
get_descriptor 001 003 1 0 0 128 0x03 2
(... and so forth...)
get_descriptor 001 003 1 0 0 128 0x04 0
get_descriptor 001 003 1 0 0 128 0x05 0
get_descriptor 001 003 1 0 0 128 0x21 0
get_descriptor 001 003 1 0 0 128 0x22 0

Here I am assuming that your UPS is still device 003 on bus 001; if
not, please update the first two arguments accordingly.

Note that the program must be run as root, and another driver
(e.g. NUT) should not be attached to the device at the same time.

Also note that this must be compiled with "-lusb", i.e.:
gcc -g -O2 -Wall  -lusb  get_descriptor.c   -o get_descriptor

-- Peter
-------------- next part --------------
/* 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 1 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 = NULL;
  struct usb_interface *inter = NULL;
  struct usb_interface_descriptor *alt = NULL;
  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 */
  for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
    con = &dev->config[i];
    if (con->bConfigurationValue == arg_con) {
      break;
    }
  }
  if (i >= dev->descriptor.bNumConfigurations) {
    fprintf(stderr, "Bus %s device %s has no configuration %d.\n", arg_bus, arg_dev, arg_con);
    fprintf(stderr, "Possible values:");
    for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
      con = &dev->config[i];
      fprintf(stderr, " %d", con->bConfigurationValue);
    }
    fprintf(stderr, "\n");
    exit(2);
  }

  /* find the requested interface */
  for (i=0; i<con->bNumInterfaces; i++) {
    inter = &con->interface[i];
    alt = &inter->altsetting[0];
    if (alt->bInterfaceNumber == arg_int) {
      break;
    }
  }
  if (i >= 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:");
    for (i=0; i<con->bNumInterfaces; i++) {
      inter = &con->interface[i];
      alt = &inter->altsetting[0];
      fprintf(stderr, " %d", alt->bInterfaceNumber);
    }
    fprintf(stderr, "\n");
    exit(2);
  }
  
  /* find the requested alternative setting */
  for (i=0; i<inter->num_altsetting; i++) {
    alt = &inter->altsetting[i];
    if (alt->bAlternateSetting == arg_alt) {
      break;
    }
  }
  if (i >= 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:");
    for (i=0; i<inter->num_altsetting; i++) {
      alt = &inter->altsetting[i];
      fprintf(stderr, " %d", alt->bAlternateSetting);
    }
    fprintf(stderr, "\n");
    exit(2);
  }

  /* 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, arg_con);
  if (r<0) {
    fprintf(fout, "Warning: %s\n", usb_strerror());
    err = 3;
  }
  
  /* claim the interface */
  r = usb_claim_interface_with_detach(udev, arg_int);
  if (r<0) {
    fprintf(fout, "Warning: %s\n", usb_strerror());
    err = 3;
  }

  /* set altsetting */
  r = usb_set_altinterface(udev, arg_alt);
  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