chiark / gitweb /
incorporated hiddev stuff and new redact mode into evdev-manip
authorian <ian>
Mon, 16 Jun 2008 00:16:00 +0000 (00:16 +0000)
committerian <ian>
Mon, 16 Jun 2008 00:16:00 +0000 (00:16 +0000)
hostside/Makefile
hostside/evdev-manip.c
hostside/hiddev-test.c

index 33fc7914589f8ed18760af14e6faa36f590c3914..d53e16f0f54bdf1fa6f21735f1cae9b45fc4f533 100644 (file)
@@ -6,7 +6,7 @@ AUTOINCS=       auproto-pic.h layoutinfo.h retransmit-table.h           \
                errorcodes.h stastate.h record-y.h record-l.h           \
                realtime+dflags.h input-codes.h
 
-CLIENT_TARGETS=        gui-plan-bot topology-dump evdev-manip hiddev-test
+CLIENT_TARGETS=        gui-plan-bot topology-dump evdev-manip
 
 TARGETS=       hostside-old realtime                                   \
                $(CLIENT_TARGETS)                                       \
@@ -35,8 +35,6 @@ topology-dump:        topology-dump.o utils.o $(LAYOUT_DATA).o
 
 evdev-manip:   evdev-manip.o utils.o $(LIBOOP_OBJS)
 
-hiddev-test:   hiddev-test.o utils.o
-
 gui-plan-bot: gui-plan-%:  gui-plan.o utils.o parseutils.o obc.o       \
                        ../layout/ours.dgram-%.plandata.o               \
                        $(LAYOUT_DATA).o $(LIBOOP_OBJS)
index cd3ac0fcd9ed6257f65644976a3452b056cd1518..1634dbb6a792152b99080ef59da3b8c087ecc11c 100644 (file)
@@ -1,15 +1,32 @@
 /*
  * evdev-manip [<options> <device> ...]
+ *
  *  modes:
- *     --dump          default
- *  per-device options:
- *     --[no-]grab     --nograb is default
+ *     --dump-raw      default
+ *     --redact        print redacted version
+ *                      output is   <path|label> <value> <str> <str>...
+ *                      where <str>... identifies the button, axis, etc.
+ *
+ *  global options:
+ *     --stdin-monitor      quit if stdin becomes readable
+ *
+ *  per-device options (applies only to next device):
+ *    --label LABEL         use LABEL instead of path in redacted output
+ *
+ *  per-device options (apply to all subsequent):
+ *     --elide|show-unchanged      --elide-unchanged is default
+ *     --evdev                     subsequent devices are evdev
+ *     --hiddev                    subsequent devices are hiddev
+ *                                  hiddev <str> are application and field
+ *                                  both in hex,  page<<16 | usage
+ *
+ *  per-evdev options (apply to all subsequent):
+ *     --[no-]grab                 --nograb is default
  *     --expect-sysfs /sys/class/input/inputX/eventY/dev
  *                        ^^^^^^^^^^^^^^^^^^^^
  *                          this part is in /proc/bus/usb/devices
  *                           and can thus be specified by caller
- * 
- *     --stdin-monitor      quit if stdin becomes readable
+ *                          for evdev devices
  */
 
 #include "common.h"
 #include <oop-read.h>
 #include <poll.h>
 #include <sys/fcntl.h>
+#include <search.h>
 
 #include <linux/input.h>
+#include <linux/hiddev.h>
 
 typedef struct InputEventState InputEventState;
 #include "input-codes.h" /* not really a header */
 
-typedef struct {
-  char *path;
-  int fd;
-} Device;
-
-typedef struct {
-  void (*event)(Device *d, const struct input_event *ie);
+typedef struct Device Device;
+typedef struct KindInfo KindInfo;
+typedef struct ModeInfo ModeInfo;
+typedef const ModeInfo *Mode;
+typedef const KindInfo *Kind;
+
+struct ModeInfo {
+  void (*evdev_event)(Device *d, const struct input_event *ie);
+  void (*evdev_readable)(Device *d);
+  void (*evdev_synch)(Device *d, struct timeval tv);
+  void (*hiddev_event)(Device *d, const struct hiddev_usage_ref *ur);
+  int (*hiddev_xflags)(void);
+  void (*redacted)(Device *d, int nstrs, const char *strs[nstrs], int value);
   void (*died)(Device *d, int revents, int readr, int readc, int e)
        __attribute__((noreturn));
   void (*mainloop)(void);
-} ModeInfo;
+};
 
-typedef const ModeInfo *Mode;
+struct KindInfo {
+  void (*prepare)(Device*);
+  void (*readable)(Device*);
+};
 
-static int ndevices;
-static Device *devices;
+typedef struct {
+  int elide;
+} DeviceFlags;
 
+typedef struct {
+  struct hiddev_field_info fi;
+  int *lastvalues;
+} HiddevField;
+
+struct Device {
+  char *path;
+  const char *label;
+  int fd;
+  const KindInfo *kind;
+  DeviceFlags flags;
+  union {
+    struct {
+      void *froot;
+      HiddevField *fbuf;
+    } hiddev;
+  } forkind;
+};
+
+/*---------- globals ----------*/
+
+/* command line options */
 static Mode mode;
+static Kind kind;
 static int grab, stdinmonitor;
-static const char *expect_sysfs;
+static const char *expect_sysfs, *label;
+static DeviceFlags dflags= { 1 };
+
+static int ndevices;
+static Device *devices;
+
+/*---------- generally useful ----------*/
 
 static void pr_hex(unsigned long value) { printf("%#lx",value); }
 
@@ -60,10 +118,31 @@ static void pr_time(struct timeval tv) {
   printf("%ju.%06d", (uintmax_t)tv.tv_sec, (int)tv.tv_usec);
 }
 
-static void dump_event(Device *d, const struct input_event *ie) {
+static void mread(Device *d, void *buf, size_t l) {
+  char *p;
+  int r, remain;
+
+  for (p=buf, remain=l;
+       remain;
+       p+=r, remain-=r) {
+    r= read(d->fd, p, remain);
+    if (r<=0) { mode->died(d, POLLIN, r, -1, errno); abort(); }
+    assert(r <= remain);
+  }
+}
+
+static void dump_vpv(unsigned vendor, unsigned product, unsigned version) {
+  printf(" vendor %#x product %#x version %#x",
+        vendor, product, version);
+}
+#define DUMP_VPV(t) (dump_vpv((t).vendor, (t).product, (t).version))
+
+/*---------- evdev kind ----------*/
+
+static void evdev_dump(Device *d, const struct input_event *ie) {
   const InputEventTypeInfo *t;
 
-  printf("event ");
+  printf("evdev ");
   pr_time(ie->time);
 
   printf(" ");
@@ -92,33 +171,292 @@ static void dump_event(Device *d, const struct input_event *ie) {
   printf("\n");
 }
 
-static void process_device(Device *d) {
+#define MAXTABSTRH 20
+static void tab_redact(const InputEventStringInfo *strings, int nstrings,
+                      unsigned long value, char hexbuf[MAXTABSTRH],
+                      const char *sb[2]) {
+  const InputEventStringInfo *string;
+  if (value <= nstrings &&
+      (string= &strings[value],
+       string->prefix)) {
+    sb[0]= string->prefix;
+    sb[1]= string->main;
+  } else {
+    snprintf(hexbuf,sizeof(hexbuf),"%lx",value);
+    sb[0]= "0x";
+    sb[1]= hexbuf;
+  }
+}
+
+static void evdev_redact(Device *d, const struct input_event *ie) {
+  const InputEventTypeInfo *t;
+  char sbh_type[MAXTABSTRH];
+  char sbh_code[MAXTABSTRH];
+  const char *strs[4];
+  
+  tab_redact(iesis_ev, ien_ev, ie->type, sbh_type, &strs[0]);
+
+  if (ie->type >= IETIN) {
+    t= 0;
+  } else {
+    t= &ietis[ie->type];
+    if (!t->strings) t= 0;
+  }
+  tab_redact(t ? t->strings : 0,
+            t ? t->nstrings : 0,
+            ie->code, sbh_code, &strs[2]);
+
+  mode->redacted(d, 4,strs, ie->value);
+}
+
+static void evdev_readable(Device *d) {
   struct input_event ie;
-  int r, remain;
-  char *p;
 
-  printf("report-from device %s\n",d->path);
+  if (mode->evdev_readable) mode->evdev_readable(d);
 
   for (;;) {
-    for (p=(void*)&ie, remain=sizeof(ie);
-        remain;
-        p+=r, remain-=r) {
-      r= read(d->fd, &ie, remain);
-      if (r<=0) { mode->died(d, POLLIN, r, -1, errno); abort(); }
-      assert(r <= remain);
-    }
+    mread(d, &ie, sizeof(ie));
     if (ie.type == EV_SYN) {
-      printf("synch ");
-      pr_time(ie.time);
-      printf("\n");
+      if (mode->evdev_synch) mode->evdev_synch(d, ie.time);
       break;
     }
 
-    mode->event(d, &ie);
+    mode->evdev_event(d, &ie);
+  }
+}
+
+static void evdev_readable_dump(Device *d) {
+  printf("report-from device %s\n",d->path);
+}
+static void evdev_synch_dump(Device *d, struct timeval tv) {
+  printf("synch ");
+  pr_time(tv);
+  printf("\n");
+}
+
+static void check_expect_sysfs(int fd, const char *path, const char *efn) {
+  char buf[50], *ep;
+  unsigned long maj, min;
+  struct stat stab;
+  FILE *sysfs;
+  int r;
+    
+  r= fstat(fd, &stab);  if (r) diee("%s: fstat failed", path);
+  if (!S_ISCHR(stab.st_mode)) die("%s: not a character device", path);
+    
+  sysfs= fopen(efn,"r");
+  if (!sysfs) diee("%s: failed to open sysfs %s", path, efn);
+  if (!fgets(buf,sizeof(buf)-1,sysfs)) {
+    if (ferror(sysfs)) diee("%s: failed to read sysfs %s", path, efn);
+    assert(feof(sysfs)); die("%s: eof on sysfs %s", path, efn);
   }
+  buf[sizeof(buf)-1]= 0;
+  errno=0; maj=strtoul(buf,&ep,0);
+  if (errno || *ep!=':') die("%s: bad major number or no colon in sysfs"
+                            " dev file %s", path, efn);
+  errno=0; min=strtoul(ep+1,&ep,0);
+  if (errno || *ep!='\n') die("%s: bad minor number or no colon in sysfs"
+                             " dev file %s", path, efn);
+
+  if (maj != major(stab.st_rdev) || min != minor(stab.st_rdev))
+    die("%s: is %lu:%lu, expected %lu:%lu", path,
+       (unsigned long)major(stab.st_rdev),
+       (unsigned long)minor(stab.st_rdev),
+       maj, min);
+
+  if (fclose(sysfs)) die("%s: failed to close sysfs %s", path, efn);
+}
+
+static void evdev_prepare(Device *d) {
+  int r;
+  struct input_id iid;
+  
+  if (expect_sysfs) {
+    check_expect_sysfs(d->fd, d->path, expect_sysfs);
+    expect_sysfs= 0;
+  }
+
+  r= ioctl(d->fd, EVIOCGID, &iid);
+  if (r) diee("%s: failed to get id",d->path);
+  
+  printf("device %s bustype ", d->path);
+  PR_TABLE_STR(bus, iid.bustype);
+  DUMP_VPV(iid);
+  putchar('\n');
   mflushstdout();
+
+  if (grab) {
+    r= ioctl(d->fd, EVIOCGRAB, 1);
+    if (r) diee("%s: failed to grab",d->path);
+  }
+}
+
+static const KindInfo kind_evdev= { evdev_prepare, evdev_readable };
+
+/*---------- hiddev kind ----------*/
+
+static int hiddev_f_compar(const void *a_v, const void *b_v) {
+  const HiddevField *a=a_v, *b=b_v;
+  /* these are all unsigned 0..0xffff so the differences fit nicely */
+  return (int)a->fi.report_type - (int)b->fi.report_type ? :
+         (int)a->fi.report_id   - (int)b->fi.report_id   ? :
+         (int)a->fi.field_index - (int)b->fi.field_index;
+}
+
+static HiddevField *hiddev_get_f(Device *d,
+                                const struct hiddev_usage_ref *ur) {
+  HiddevField *f;
+  void **fvp;
+  int r;
+  
+  if (ur->field_index == HID_FIELD_INDEX_NONE)
+    return 0;
+
+  if (!d->forkind.hiddev.fbuf) {
+    d->forkind.hiddev.fbuf= mmalloc(sizeof(*d->forkind.hiddev.fbuf));
+  }
+
+  memset(&d->forkind.hiddev.fbuf->fi,0x55,sizeof(d->forkind.hiddev.fbuf->fi));
+  d->forkind.hiddev.fbuf->fi.report_type= ur->report_type;
+  d->forkind.hiddev.fbuf->fi.report_id=   ur->report_id;
+  d->forkind.hiddev.fbuf->fi.field_index= ur->field_index;
+  fvp= tsearch(d->forkind.hiddev.fbuf,
+              &d->forkind.hiddev.froot,
+              hiddev_f_compar);
+  if (!fvp) diee("tsearch hiddev type/id/index");
+  f= *fvp;
+
+  if (f == d->forkind.hiddev.fbuf) {
+    d->forkind.hiddev.fbuf= 0;
+    
+    r= ioctl(d->fd, HIDIOCGFIELDINFO, &f->fi);
+    if (r) diee("%s: ioctl HIDIOCGFIELDINFO %#x %#x %#x", d->path,
+               f->fi.report_type, f->fi.report_id, f->fi.field_index);
+
+    size_t sz= sizeof(*f->lastvalues) * f->fi.maxusage;
+    f->lastvalues= mmalloc(sz);
+    memset(f->lastvalues,0,sz);
+  }
+  assert(ur->usage_index < f->fi.maxusage);
+
+  return f;
+}
+
+static int hiddev_elide(Device *d, const struct hiddev_usage_ref *ur,
+                       HiddevField *f) {
+  if (!f)
+    return 0;
+  
+  if (!d->flags.elide)
+    return 0;
+
+  unsigned relevant_flags= f->fi.flags &
+    (HID_FIELD_RELATIVE|HID_FIELD_BUFFERED_BYTE);
+
+  if (relevant_flags == HID_FIELD_RELATIVE &&
+      !ur->value) {
+    return 1;
+  }
+  if (relevant_flags == 0) {
+    if (ur->value == f->lastvalues[ur->usage_index])
+      return 1;
+    f->lastvalues[ur->usage_index]= ur->value;
+  }
+  return 0;
+}
+
+static void hiddev_dump(Device *d, const struct hiddev_usage_ref *ur) {
+  HiddevField *f;
+
+  f= hiddev_get_f(d, ur);
+
+  if (hiddev_elide(d, ur, f))
+    return;
+
+  printf("hiddev type %04x id %04x", ur->report_type, ur->report_id);
+  if (ur->field_index == HID_FIELD_INDEX_NONE) {
+    printf(" field index NONE\n");
+    return;
+  }
+
+  printf(" field index %04x"
+        " usage index %04x code %04x value %08lx ",
+        ur->field_index,
+        ur->usage_index, ur->usage_code,
+        (unsigned long)ur->value);
+
+  printf(" maxusage %04x flags %04x"
+        " physical %04x %08lx..%08lx"
+        " logical %04x %08lx..%08lx"
+        " application %04x"
+        " unit %04x exponent %04x",
+        f->fi.maxusage, f->fi.flags,
+        f->fi.physical, (unsigned long)f->fi.physical_minimum,
+        (unsigned long)f->fi.physical_maximum,
+        f->fi.logical, (unsigned long)f->fi.logical_minimum,
+        (unsigned long)f->fi.logical_maximum,
+        f->fi.application,
+        f->fi.unit, f->fi.unit_exponent);
+
+  putchar('\n');
+}
+
+static void hiddev_redact(Device *d, const struct hiddev_usage_ref *ur) {
+  HiddevField *f;
+  char sb_app[9], sb_usage[9];
+  const char *strs[2];
+
+  if (ur->field_index == HID_FIELD_INDEX_NONE)
+    return;
+
+  f= hiddev_get_f(d, ur);
+  if (hiddev_elide(d, ur, f))
+    return;
+
+  assert(f->fi.application <= 0xffffffffUL);
+  assert(ur->usage_code <= 0xffffffffUL);
+  sprintf(sb_app, "%lx", (unsigned long)f->fi.application);
+  sprintf(sb_usage, "%lx", (unsigned long)ur->usage_code);
+
+  strs[0]= sb_app;
+  strs[1]= sb_usage;
+  mode->redacted(d, 2,strs, ur->value);
+}
+
+static void hiddev_readable(Device *d) {
+  struct hiddev_usage_ref ur;
+  mread(d, &ur, sizeof(ur));
+  mode->hiddev_event(d, &ur);
+}
+
+static void hiddev_prepare(Device *d) {
+  int r, flags;
+  struct hiddev_devinfo di;
+
+  flags= HIDDEV_FLAG_UREF;
+  if (mode->hiddev_xflags) flags |= mode->hiddev_xflags();
+  r= ioctl(d->fd, HIDIOCSFLAG, &flags);
+  if (r) diee("hiddev %s: ioctl HIDIOCSFLAG", d->path);
+
+  r= ioctl(d->fd, HIDIOCGDEVINFO, &di);
+  if (r) diee("hiddev %s: ioctl HIDIOCGDEVINFO", d->path);
+
+  printf("device %s bustype ", d->path);
+  PR_TABLE_STR(bus, di.bustype);
+  printf(" bus %d dev %d if %d", di.busnum, di.devnum, di.ifnum);
+  DUMP_VPV(di);
+  printf(" napplications %d\n", di.num_applications);
+
+  d->forkind.hiddev.froot= 0;
+  d->forkind.hiddev.fbuf= 0;
 }
 
+static int hiddev_xflags_dump(void) { return HIDDEV_FLAG_REPORT; }
+
+static const KindInfo kind_hiddev= { hiddev_prepare, hiddev_readable };
+
+/*---------- mode dump ----------*/
+
 static void dump_died(Device *d, int revents, int readr, int readc, int e)
      __attribute__((noreturn));
 static void dump_died(Device *d, int revents, int readr, int readc, int e) {
@@ -174,50 +512,42 @@ static void mainloop(void) {
        mode->died(&devices[i], polls[i].revents, r, dummy, errno);
        abort();
       }
-      if (polls[i].revents)
-       process_device(&devices[i]);
+      if (polls[i].revents) {
+       Device *d= &devices[i];
+       d->kind->readable(d);
+       mflushstdout();
+      }
     }
   }
 }
 
-static const ModeInfo mode_dump= { dump_event, dump_died, mainloop };
-
-static void check_expect_sysfs(int fd, const char *path, const char *efn) {
-  char buf[50], *ep;
-  unsigned long maj, min;
-  struct stat stab;
-  FILE *sysfs;
-  int r;
-    
-  r= fstat(fd, &stab);  if (r) diee("%s: fstat failed", path);
-  if (!S_ISCHR(stab.st_mode)) die("%s: not a character device", path);
-    
-  sysfs= fopen(efn,"r");
-  if (!sysfs) diee("%s: failed to open sysfs %s", path, efn);
-  if (!fgets(buf,sizeof(buf)-1,sysfs)) {
-    if (ferror(sysfs)) diee("%s: failed to read sysfs %s", path, efn);
-    assert(feof(sysfs)); die("%s: eof on sysfs %s", path, efn);
-  }
-  buf[sizeof(buf)-1]= 0;
-  errno=0; maj=strtoul(buf,&ep,0);
-  if (errno || *ep!=':') die("%s: bad major number or no colon in sysfs"
-                            " dev file %s", path, efn);
-  errno=0; min=strtoul(ep+1,&ep,0);
-  if (errno || *ep!='\n') die("%s: bad minor number or no colon in sysfs"
-                             " dev file %s", path, efn);
+static const ModeInfo mode_dump= {
+  evdev_dump, evdev_readable_dump, evdev_synch_dump,
+  hiddev_dump, hiddev_xflags_dump,
+  0, dump_died, mainloop
+};
+
+/*---------- mode redact ----------*/
+
+static void redact_redacted(Device *d, int nstrs, const char *strs[nstrs],
+                           int value) {
+  int i;
+  
+  printf("%s %d", d->label, value);
+  for (i=0; i<nstrs; i++)
+    printf(" %s", strs[i]);
+  putchar('\n');
+}
 
-  if (maj != major(stab.st_rdev) || min != minor(stab.st_rdev))
-    die("%s: is %lu:%lu, expected %lu:%lu", path,
-       (unsigned long)major(stab.st_rdev),
-       (unsigned long)minor(stab.st_rdev),
-       maj, min);
+static const ModeInfo mode_redact= {
+  evdev_redact, 0, 0,
+  hiddev_redact, 0,
+  redact_redacted, dump_died, mainloop
+};
 
-  if (fclose(sysfs)) die("%s: failed to close sysfs %s", path, efn);
-}
+/*---------- main program ----------*/
 
 static void getdevice(const char *path) {
-  int r;
-  struct input_id iid;
   Device *d;
   ndevices++;
   devices= mrealloc(devices, sizeof(*devices)*ndevices);
@@ -225,27 +555,24 @@ static void getdevice(const char *path) {
 
   d->path= mstrdup(path);
   d->fd= open(path, O_RDONLY);  if (d->fd<0) diee("%s: failed to open",path);
+  d->kind= kind;
+  d->flags= dflags;
 
-  if (expect_sysfs) {
-    check_expect_sysfs(d->fd, path, expect_sysfs);
-    expect_sysfs= 0;
+  if (label) {
+    d->label= label;
+    label= 0;
+  } else {
+    d->label= d->path;
   }
 
-  r= ioctl(d->fd, EVIOCGID, &iid);  if (r) diee("%s: failed to get id",path);
-  printf("device %s bustype ", path);
-  PR_TABLE_STR(bus, iid.bustype);
-  printf(" vendor %#x product %#x version %#x\n",
-        iid.vendor, iid.product, iid.version);
-  mflushstdout();
-
-  if (grab)
-    r= ioctl(d->fd, EVIOCGRAB, 1);  if (r) diee("%s: failed to grab",path);
+  kind->prepare(d);
 }
 
 int main(int argc, const char **argv) {
   const char *arg;
 
   mode= &mode_dump;
+  kind= &kind_evdev;
 
   while ((arg= *++argv)) {
     if (arg[0] != '-') {
@@ -254,9 +581,17 @@ int main(int argc, const char **argv) {
     else if (!strcmp(arg,"--expect-sysfs")) {
       if (!(expect_sysfs= *++argv)) badusage("missing arg for --expect-sysfs");
     }
-    else if (!strcmp(arg,"--dump")) { mode= &mode_dump; }
+    else if (!strcmp(arg,"--label")) {
+      if (!(label= *++argv)) badusage("missing arg for --expect-sysfs");
+    }
+    else if (!strcmp(arg,"--dump-raw")) { mode= &mode_dump; }
+    else if (!strcmp(arg,"--redact")) { mode= &mode_redact; }
+    else if (!strcmp(arg,"--evdev")) { kind= &kind_evdev; }
+    else if (!strcmp(arg,"--hiddev")) { kind= &kind_hiddev; }
     else if (!strcmp(arg,"--grab")) { grab= 1; }
     else if (!strcmp(arg,"--no-grab")) { grab= 0; }
+    else if (!strcmp(arg,"--show-unchanged")) { dflags.elide= 0; }
+    else if (!strcmp(arg,"--elide-unchanged")) { dflags.elide= 1; }
     else if (!strcmp(arg,"--stdin-monitor")) { stdinmonitor= 1; }
     else badusage("unknown option");
   }
index d2bc01b70e9a561eb9f0164604888d88f71237c9..3636b727d93ca29b0cf116b33632135652863730 100644 (file)
 
 int main(int argc, char **argv) {
   struct hiddev_usage_ref ev;
-  struct hiddev_field_info fi;
-  int r, flag;
-
-  flag= HIDDEV_FLAG_UREF|HIDDEV_FLAG_REPORT;
-  r= ioctl(0, HIDIOCSFLAG, &flag);
-  if (r) diee("ioctl HIDIOCSFLAG");
 
   if (!argv[0] || argv[1]) badusage("no arguments allowed");
 
@@ -34,36 +28,6 @@ int main(int argc, char **argv) {
     if (ev.field_index == HID_FIELD_INDEX_NONE)
       printf("report type %04x id %04x field index NONE\n",
             ev.report_type, ev.report_id);
-    else {
-      printf("report type %04x id %04x field index %04x"
-            " usage index %04x code %04x value %08lx ",
-            ev.report_type, ev.report_id,
-            ev.field_index,
-            ev.usage_index, ev.usage_code,
-            (unsigned long)ev.value);
-      memset(&fi,0x55,sizeof(fi));
-      fi.report_type= ev.report_type;
-      fi.report_id=   ev.report_id;
-      fi.field_index= ev.field_index;
-      r= ioctl(0, HIDIOCGFIELDINFO, &fi);
-      if (r) {
-       printf(" ? %s",strerror(errno));
-      } else {
-       printf(" maxusage %04x flags %04x"
-              " physical %04x %08lx..%08lx"
-              " logical %04x %08lx..%08lx"
-              " application %04x"
-              " unit %04x exponent %04x",
-              fi.maxusage, fi.flags,
-              fi.physical, (unsigned long)fi.physical_minimum,
-              (unsigned long)fi.physical_maximum,
-              fi.logical, (unsigned long)fi.logical_minimum,
-              (unsigned long)fi.logical_maximum,
-              fi.application,
-              fi.unit, fi.unit_exponent);
-      }
-      putchar('\n');
-    }
   }
 }