We store some information about certain mice in here for debuggging purpose.
Run a sudo dmesg -w
and unplug/replug your mouse. The kernel messages look like
[ 6353.296752] usb 5-1.1: USB disconnect, device number 4
[ 6355.573380] usb 5-1.1: new full-speed USB device number 10 using xhci_hcd
[ 6355.857686] usb 5-1.1: New USB device found, idVendor=1038, idProduct=1724, bcdDevice= 2.34
[ 6355.857698] usb 5-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 6355.857705] usb 5-1.1: Product: SteelSeries Rival 600
[ 6355.857709] usb 5-1.1: Manufacturer: SteelSeries
[ 6355.884557] hid-generic 0003:1038:1724.0016: hiddev0,hidraw3: USB HID v1.11 Device [SteelSeries SteelSeries Rival 600] on usb-0000:06:00.0-1.1/input0
[ 6355.886002] input: SteelSeries SteelSeries Rival 600 as /devices/pci0000:00/0000:00:1c.4/0000:06:00.0/usb5/5-1/5-1.1/5-1.1:1.1/0003:1038:1724.0017/input/input51
[ 6355.886541] hid-generic 0003:1038:1724.0017: input,hidraw6: USB HID v1.11 Mouse [SteelSeries SteelSeries Rival 600] on usb-0000:06:00.0-1.1/input1
[ 6355.888456] input: SteelSeries SteelSeries Rival 600 Keyboard as /devices/pci0000:00/0000:00:1c.4/0000:06:00.0/usb5/5-1/5-1.1/5-1.1:1.2/0003:1038:1724.0018/input/input52
[ 6355.943755] input: SteelSeries SteelSeries Rival 600 Consumer Control as /devices/pci0000:00/0000:00:1c.4/0000:06:00.0/usb5/5-1/5-1.1/5-1.1:1.2/0003:1038:1724.0018/input/input53
[ 6355.944183] hid-generic 0003:1038:1724.0018: input,hidraw9: USB HID v1.11 Keyboard [SteelSeries SteelSeries Rival 600] on usb-0000:06:00.0-1.1/input2d
From that you can extract important information for the next steps: The idVendor
and idProduct
With aboves instruction, you need to run the following command with passing idVendor:idProduct
to lsusb
# Replace 1038:1724 with idVendor:idProduct and steelseries_rival600.txt with <Vendor Name>_<Product Name>.txt
lsusb -vd 1038:1724 > steelseries_rival600.txt
This writes the following content to the dump file
Bus 005 Device 010: ID 1038:1724 SteelSeries ApS SteelSeries Rival 600
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x1038 SteelSeries ApS
idProduct 0x1724
bcdDevice 2.34
iManufacturer 1 SteelSeries
iProduct 2 SteelSeries Rival 600
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0054
bNumInterfaces 3
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 200mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 37
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 1 Boot Interface Subclass
bInterfaceProtocol 2 Mouse
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 98
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0009 1x 9 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 76
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0009 1x 9 bytes
bInterval 1
You see, that the report descriptor in the dump of the previous paragraph is missing (Report Descriptors: ** UNAVAILABLE **
).
This descriptor basically tells you, in what kind of format the mouse is sending you data to the host. So we definitely want to have this descriptor!
Run
# Replace 1038:1724 with idVendor:idProduct and steelseries_rival600_raw.txt with <Vendor Name>_<Product Name>_raw.txt
sudo usbhid-dump -d 1038:1724 > steelseries_rival600_descriptor_raw.txt
This will spew the raw Report Descriptor in hex form to the file
005:004:002:DESCRIPTOR 1617489710.244663
05 01 09 06 A1 01 85 01 05 07 19 E0 29 E7 15 00
25 01 75 01 95 08 81 02 75 08 95 01 81 01 05 07
19 00 2A FF 00 15 00 26 FF 00 75 08 95 06 81 00
C0 05 0C 09 01 A1 01 85 02 05 0C 19 00 2A FF 0F
15 00 26 FF 0F 75 10 95 02 81 00 C0
005:004:001:DESCRIPTOR 1617489710.245521
# Starting from here. this is the interesting part (comment for next paragraph!)
05 01 09 02 A1 01 09 01 A1 00 A1 02 05 09 19 01
29 08 15 00 25 01 95 08 75 01 81 02 05 01 09 30
09 31 16 01 80 26 FF 7F 75 10 95 02 81 06 09 38
15 81 25 7F 75 08 95 01 81 06 C0 A1 02 05 0C 0A
38 02 15 81 25 7F 75 08 95 01 81 06 C0 A1 02 06
C1 FF 15 00 26 FF 00 75 08 09 F0 95 02 81 02 C0
C0 C0
005:004:000:DESCRIPTOR 1617489710.246510
06 C0 FF 09 01 A1 01 06 C1 FF 15 00 26 FF 00 75
08 09 F0 95 20 81 02 09 F1 95 20 91 02 09 F2 96
42 02 B1 02 C0
I recently stumpled upon this nice USB Descriptor Parser which directly relates each HEX value to the human readable structure.
Copy over the interesting HEX sequence (see previous paragraph on the hex values), and click on the USB HID Report Descriptor
button.
This will give you an output like this
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0xA1, 0x02, // Collection (Logical)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x08, // Usage Maximum (0x08)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x08, // Report Count (8)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x01, 0x80, // Logical Minimum (-32767)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xA1, 0x02, // Collection (Logical)
0x05, 0x0C, // Usage Page (Consumer)
0x0A, 0x38, 0x02, // Usage (AC Pan)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xA1, 0x02, // Collection (Logical)
0x06, 0xC1, 0xFF, // Usage Page (Vendor Defined 0xFFC1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x09, 0xF0, // Usage (0xF0)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
0xC0, // End Collection
// 98 bytes
Note on how you can now clearly see the datastructur of this device, when it reports to the system
Type | Length (bits) |
Button | 8*1 = 8 |
X,Y displacement | 2*16 = 32 |
Mousewheel | 1*8 = 8 |
Vendor Specific | 2*8 = 16 |
You will need to install hidrd
and xxd
. For arch, you can use the AUR package yay -Sy hidrd-git
and sudo pacman -Sy xxd
For the aboves example, there were 3 inerfaces. Therfore run the following for each interface (note the increment in the parameter -i
sudo usbhid-dump -d 1038:1724 -i0 | grep -v : | xxd -r -p | hidrd-convert -o spec >> steelseries_rival600_descriptor.txt
sudo usbhid-dump -d 1038:1724 -i1 | grep -v : | xxd -r -p | hidrd-convert -o spec >> steelseries_rival600_descriptor.txt
sudo usbhid-dump -d 1038:1724 -i2 | grep -v : | xxd -r -p | hidrd-convert -o spec >> steelseries_rival600_descriptor.txt
NOTE The output is helpful, but a clear HEX to Human readable representation would be nice, wouldn’t it? This is, why I prefere the online parser (see previous paragraph)
USB is a pretty interesting protocol. According to the specifications a device can host several distinct interfaces
.
And theses interfaces can be of different (predefined) subclass type (See pp.8 of the pdf).
Particularily, there are generic HID devices like Keyboards and Mice, which are most interesting here for now.
However, since there are a ton of different HID devices around the world, which would like to implement special features (more mouse buttons, RGB, media keys - you name it)
the USB consortium implemented a way to implement these features
- By default, the devices will enter the so called
Boot protocol
(mode for e.g. the BIOS/EFI etc). Thise mode dictates the explicit type of data, the device is supposed to send. Nothing more and nothing less. A minimal common base so to say. For a mouse it looks like this (see p. 61 of the pdf)Byte Bits Description 0 0 Button 1 1 Button 2 2 Button3 4 to 7 Device-specific 1 0 to 7 X displacement 2 0 to 7 Y displacement 3 to n Device specific (optional) - Since this presents a limited functionality, the USB consortium allows a device to declare
Interface Descriptors
of the data it will send, when switching modes away fromBoot protocol
. - This is now, where it gets interesting: The corresponding USB/HID driver of the OS will tell the device to switch the mode from
Boot Mode
toDescriptor Mode
when getting bound by usb-hid.- Ignoring this fact particularily messed up the data getting parsed by this driver. See the corresponding bugreport.
- The device stays in this mode, even when we bind to
LEETMOUSE
.- This can cause unforseen consequences to the inputs send from the mouse to the host, since
LEETMOUSE
interprets them (right now) in a static/fixed way. - This is about to change however… Hence this documentation
- This can cause unforseen consequences to the inputs send from the mouse to the host, since