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