-----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);
}