Linux – USB keypad (HID) not responding in linux but in grub

hidinputlinuxusb

An external USB keypad I'd like to use gets recognised as a USB HID device, but it is not functional when Linux is booted. It does work when plugged into a Windows desktop and it does work while in grub, but not when the system has booted.

The device is visible on the USB port (05a4:8003):

$ lsusb
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 003 Device 002: ID 046d:c078 Logitech, Inc. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 05a4:8003 Ortek Technology, Inc.

And dmesg shows no error when the device gets connected:

[  466.932272] usb 1-1.2: new full-speed USB device number 4 using ehci_hcd
[  467.026740] usb 1-1.2: New USB device found, idVendor=05a4, idProduct=8003
[  467.026745] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  467.026756] usb 1-1.2: Product: USB Keypad     
[  467.026758] usb 1-1.2: Manufacturer: Keypad
[  467.027939] input: Keypad USB Keypad      as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/input/input13
[  467.028099] hid-generic 0003:05A4:8003.0004: input,hidraw1: USB HID v1.10 Keyboard [Keypad USB Keypad     ] on usb-0000:00:1a.0-1.2/input0
[  467.029600] input: Keypad USB Keypad      as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.1/input/input14
[  467.029726] hid-generic 0003:05A4:8003.0005: input,hidraw2: USB HID v1.10 Mouse [Keypad USB Keypad     ] on usb-0000:00:1a.0-1.2/input1

The input/event devices are created, but not responding.
I wonder whether it is problematic that the device gets registered twice, as Keyboard input and as Mouse input.

I'm testing on a Ubuntu 13.04 system. The intended target system is a Raspberry Pi with Rasbian. Since the problem appears on Rasbian in the same way I'm thinking it is Linux related.

How can I debug this further?
Any idea what could cause this unresponsive behaviour?

Best Answer

The reason why this USB HID device works in Windows is because there may be specific drivers written for it, the reason why it works for GRUB is that the device operates in so-called boot mode. USB HID devices support two modes of operation, boot mode and HID mode. The former makes it possible to use the device in BIOS without having BIOS implement a full HID stack. The latter provides more flexibility such that extended features can be added (like extra buttons). Support for boot mode is indicated by the presence of the Boot Interface Subclass flag in the interface descriptor (see lsusb -v -d 05a4:8003):

Interface Descriptor:
...
  bInterfaceSubClass      1 Boot Interface Subclass

A quick grep through the Linux kernel sources (3.14-rc8) did not show a special driver for this USB HID device. Therefore, the kernel falls back to the generic HID driver (hid-generic). It seems however, that there is an incompatibility with this device and the driver used by Linux.

To see if whether the device generates any (invisible) activity, install the evtest program and run sudo evtest. When prompted for a device, enter the number matching your keypad. If things work, then you should see events on pressing keys.

If you do not see any keys and you want to debug this further, install wireshark to capture the USB interface (using usbmon). As you can see in the lsusb output, the input device is attached to bus 1, hence you should specify usbmon1 as interface. The command to capture USB traffic is:

sudo dumpcap -i usbmon1 -w - > usb.pcapng

(This method allows you to write usb.pcapng as a regular user, the alternative is making /dev/usbmon1 readable for the regular user or changing the ownership after the file is created.)

Analyzing a USB HID capture

As the unprivileged user, you can now start analyzing the captured USB traffic. You will need to know the basics of USB and HID to make some sense of it. The simplest HID devices usually have two endpoints, a bi-directional control endpoint (EP0, this always exists) and an interrupt endpoint for transferring data from the device to the USB host ("the computer").

I have made an example annotated capture and uploaded it to https://www.cloudshark.org/captures/a6c9580208b7. I suggest you to read the packet comments to get a better idea how it works. When you open this packet offline in Wireshark, I recommend to add some color (View -> Coloring Rules):

  • frame.comment - easier see which frames got a command
  • usb and frame.len == 64 (or its negation, usb and not frame.len == 64) - notice faster which packets got a payload.

It is also recommended to add some extra columns (right-click on a column, Column Preferences):

  • usb.urb_type - see whether a packet is submitted (URB_SUBMIT) to or a received from the device (URB_COMPLETE).
  • usb.transfer_type - see whether you are looking at control data (over EP0) or other data (such as interrupt data for USB HID devices).
  • usb.endpoint_number.direction - see the direction of the data transfer (IN is from device to host ("PC"), OUT is from host ("PC") to device).

I have dragged these columns next to the Len(gth) column and resized such that the Info column is still visible on the right of those three USB columns.

With these thing set-up, you can now start the analysis. Pressing any keys should generate an interrupt with data conforming to the format from the HID descriptor. If not, then there are probably some vendor-specific commands needed (i.e. a special driver) or there is a bug in the Linux USB (HID) stack.

Related Question