-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Wed, 22 Oct 2003 07:09 am, Bram wrote:
> The /dev/usb/hiddev0 shows that the hardware is functioning, because it
> shows that the keys do create HID events, so am I right to conclude that
> the hid-input driver stops them from getting to showkeys (and the rest
> of the userspace programs)?
If hiddev is in use, then something is wrong with the driver.

> And if so, will upgrading my kernel, currently 2.4.22, help?
Unlikely.

> PS It be happy to send you the output of cat /dev/hiddev0 |hexdump for
> the missing keys, if it would help.
That won't help. There is a utility that can dump out the device 
characteristics - see attached.

Brad

- -- 
http://lca2004.linux.org.au - I'm registered. Are you?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE/lmTqGwwszQ/PZzgRAn+eAJwOd9Osz4m6wrSx793BtHg0QgbToACghwdv
7fbNVifAoBph3BEse/nsfzU=
=h9A8
-----END PGP SIGNATURE-----
/*
 * 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 of the License, 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
 */


#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <asm/types.h>
#include <sys/signal.h>
#include <linux/hiddev.h>

struct {
    unsigned usage;
    char *label;
} my_info[] = {
    { 0x010082, "System Sleep" },
    { 0x0c0001, "Consumer Application" },
    { 0x0c00b0, "Play (bool)" },
    { 0x0c00b1, "Pause (bool)" },
    { 0x0c00b2, "Record (bool)" },
    { 0x0c00b3, "Fast Forward (bool)" },
    { 0x0c00b4, "Rewind (bool)" },
    { 0x0c00b5, "Scan Next Track (bool)" },
    { 0x0c00b6, "Scan Prev Track (bool)" },
    { 0x0c00b7, "Stop (bool)" },
    { 0x0c00cd, "Play / Pause (bool)" },
    { 0x0c00e2, "Mute (Bool)" },
    { 0x0c00e5, "DBB (bool)" },
    { 0x0c00e9, "Vol + (bool)" },
    { 0x0c00ea, "Vol - (bool)" },
    { 0x0c0183, "AL Consumer Control Configuration (really!)" },
    { 0x0c018a, "AL Email Reader (Sel)" },
    { 0x0c0192, "AL Calculator (Sel)" },
    { 0x0c0194, "AL Local Machine Browser (Sel)" },
    { 0x0c0221, "AC Search (Sel)" },
    { 0x0c0223, "AC Home (Sel)" },    
    { 0x0c0224, "AC Back (Sel)" },
    { 0x0c0225, "AC Forward (Sel)" },
    { 0x0c0226, "AC Stop (Sel)" },
    { 0x0c0227, "AC Refresh (Sel)" },
    { 0x0c0228, "AC Previous Link (Sel)" },
    { 0x0c022a, "AC Bookmarks (Sel)" },
};

#define MY_INFO_SZ (sizeof(my_info)/sizeof(my_info[0]))

static inline int info_idx(unsigned int detail) {
    unsigned int i;
    
    for (i = 0; i < MY_INFO_SZ; i++) {
        if (my_info[i].usage == detail) {
            return i;
        }
    }
    return -1;
}

int main (int argc, char **argv) {
  int fd = -1;
  int rd;
  unsigned int i, alv, yalv;
  struct hiddev_devinfo device_info;
  struct hiddev_report_info rep_info;
  struct hiddev_field_info field_info;
  struct hiddev_usage_ref usage_ref;
  struct hiddev_event ev[64];
  fd_set fdset;
  int report_type;
  int appl;
  int version;

  /* ioctl() requires a file descriptor, so we check we got one, and then open it */
  if (argc != 2) {
    fprintf(stderr, "usage: %s hiddevice - probably /dev/usb/hiddev0\n", argv[0]);
    exit(1);
  }
  if ((fd = open(argv[1], O_RDONLY)) < 0) {
    perror("hiddev open");
    exit(1);
  }
    /* ioctl() accesses the underlying driver */
  ioctl(fd, HIDIOCGVERSION, &version);
  /* the HIDIOCGVERSION ioctl() returns a packed 32 field (aka integer) */
  /* so we unpack it and display it */
  printf("hiddev driver version is %d.%d.%d\n",
	 version >> 16, (version >> 8) & 0xff, version & 0xff);

  /* suck out some device information */
  ioctl(fd, HIDIOCGDEVINFO, &device_info);
  /* the HIDIOCGDEVINFO ioctl() returns hiddev_devinfo structure - see <linux/hiddev.h> */
  /* so we work through the various elements, displaying each of them */
  printf("vendor 0x%04x product 0x%04x version 0x%04x ",
	  device_info.vendor, device_info.product, device_info.version);
  printf("has %i application%s ", device_info.num_applications, 
	 (device_info.num_applications==1?"":"s"));
  printf("and is on bus: %d devnum: %d ifnum: %d\n",
	 device_info.busnum, device_info.devnum, device_info.ifnum);

  /* Now that we have the number of applications, we can retrieve them */
  /* using the HIDIOCAPPLICATION ioctl() call */
  /* applications are indexed from 0..{num_applications-1} */
  for (yalv = 0; yalv < device_info.num_applications; yalv++) {
    appl = ioctl(fd, HIDIOCAPPLICATION, yalv);
    printf("Application %i is 0x%x ", yalv, appl);
    /* The magic values come from various usage table specs */
    switch ( appl >> 16)
      {
      case 0x0c :
	printf("(Consumer Product Page)\n");
	break;
      case 0x80 :
	printf("(USB Monitor Page)\n");
	break;
      case 0x81 :
	printf("(USB Enumerated Values Page)\n");
	break;
      case 0x82 :
	printf("(VESA Virtual Controls Page)\n");
	break;
      case 0x83 :
	printf("(Reserved Monitor Page)\n");
	break;
      case 0x84 :
	printf("(Power Device Page)\n");
	break;
      case 0x85 :
	printf("(Battery System Page)\n");
	break;
      case 0x86 :
      case 0x87 :
	printf("(Reserved Power Device Page)\n");
	break;
      default :
	printf("(Needs to be added)\n");
      }
  }

  /* Initialise the internal report structures */
  if (ioctl(fd, HIDIOCINITREPORT,0) < 0) {
    exit(1);
  }
  for (report_type = HID_REPORT_TYPE_MIN; report_type <= HID_REPORT_TYPE_MAX; report_type++) {
    rep_info.report_type = report_type;
    rep_info.report_id = HID_REPORT_ID_FIRST;
    while (ioctl(fd, HIDIOCGREPORTINFO, &rep_info) >= 0) {
      printf("  Report id: %d (%d fields)\n",
	     rep_info.report_id, rep_info.num_fields);
      for (alv = 0; alv < rep_info.num_fields; alv++) { 
	memset(&field_info, 0, sizeof(field_info));
	field_info.report_type = rep_info.report_type;
	field_info.report_id = rep_info.report_id;
	field_info.field_index = alv;
	ioctl(fd, HIDIOCGFIELDINFO, &field_info);
	printf("    Field: %d: app: %04x phys %04x flags %x "
	       "(%d usages) unit %x exp %d\n", 
	       alv, field_info.application, field_info.physical, 
	       field_info.flags, field_info.maxusage, field_info.unit,
	       field_info.unit_exponent);
	memset(&usage_ref, 0, sizeof(usage_ref));
	for (yalv = 0; yalv < field_info.maxusage; yalv++) {
	  usage_ref.report_type = field_info.report_type;
	  usage_ref.report_id = field_info.report_id;
	  usage_ref.field_index = alv;
	  usage_ref.usage_index = yalv;
	  ioctl(fd, HIDIOCGUCODE, &usage_ref);
	  ioctl(fd, HIDIOCGUSAGE, &usage_ref);
	  printf("      Usage: %04x val %d idx %x\n", usage_ref.usage_code,
		 usage_ref.value, usage_ref.usage_index);
	}
      }
      rep_info.report_id |= HID_REPORT_ID_NEXT;
    }
  }
    printf("Waiting for events ... (interrupt to exit)\n");
    fflush(stdout);

    FD_ZERO(&fdset);
    while (1) {
        FD_SET(fd, &fdset);
        rd = select(fd+1, &fdset, NULL, NULL, NULL);

        if (rd > 0) {
            rd = read(fd, ev, sizeof(ev));

            if (rd < (int) sizeof(ev[0])) {
                if (rd < 0)
                    perror("\nevtest: error reading");
                else
                    fprintf(stderr, "\nevtest: got short read from device!\n");
                exit (1);
            }

            for (i = 0; i < rd / sizeof(ev[0]); i++) {
                    int idx = info_idx(ev[i].hid);
		    if (ev[i].hid & 0xff) {
		          printf("Event: usage %x (%s), value %d\n",
				 ev[i].hid, 
				 (idx >= 0) ? my_info[idx].label : "Unknown",
				 ev[i].value);
		    }
	    }
	}
    }

  close(fd);
  exit(0);
}

Reply via email to